// CodeContracts
// 
// Copyright (c) Microsoft Corporation
// 
// All rights reserved. 
// 
// MIT License
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
#if FxCop
using Win32ResourceList = Microsoft.Cci.Win32ResourceCollection;
using TypeNodeList = Microsoft.Cci.TypeNodeCollection;
#endif
#if CCINamespace
using Microsoft.Cci;
#else
using System.Compiler;
#endif
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.Serialization;

//^ using Microsoft.Contracts;

/* These classes help with parsing and producing PE files. They are best understood in conjunction with the ECMA 335 Specification
 * (Common Language Infrastructure), particularly Partition II. Also see "Inside Microsoft .NET IL Assembler" by Serge Lidin. */

#if CCINamespace
namespace Microsoft.Cci.Metadata{
#else
namespace System.Compiler.Metadata{
#endif
  internal struct AssemblyRow{
    internal int HashAlgId;
    internal int MajorVersion;
    internal int MinorVersion;
    internal int BuildNumber;
    internal int RevisionNumber;
    internal int Flags;
    internal int PublicKey;
    internal int Name;
    internal int Culture;
  }
  internal struct AssemblyRefRow{
    internal int MajorVersion;
    internal int MinorVersion;
    internal int BuildNumber;
    internal int RevisionNumber;
    internal int Flags;
    internal int PublicKeyOrToken;
    internal int Name;
    internal int Culture;
    internal int HashValue;
    internal AssemblyReference AssemblyReference;
  }
  internal struct ClassLayoutRow{
    internal int PackingSize;
    internal int ClassSize;
    internal int Parent;
  }
  internal struct ConstantRow{
    internal int Type;
    internal int Parent;
    internal int Value;
  }
  internal struct CustomAttributeRow{
    internal int Parent;
    internal int Constructor;
    internal int Value;
  }
  internal struct DeclSecurityRow{
    internal int Action;
    internal int Parent;
    internal int PermissionSet;
  }
  internal struct EventMapRow{
    internal int Parent;
    internal int EventList;
  }
  internal struct EventPtrRow{
    internal int Event;
  }
  internal struct EventRow{
    internal int Flags;
    internal int Name;
    internal int EventType;
  }
  internal struct ExportedTypeRow{
    internal int Flags;
    internal int TypeDefId;
    internal int TypeName;
    internal int TypeNamespace;
    internal int Implementation;
  }
  internal struct FieldRow{
    internal int Flags;
    internal int Name;
    internal int Signature;
    internal Field Field;
  }
  internal struct FieldLayoutRow{
    internal int Offset;
    internal int Field;
  }
  internal struct FieldMarshalRow{
    internal int Parent;
    internal int NativeType;
  }
  internal struct FieldPtrRow{
    internal int Field;
  }
  internal struct FieldRvaRow{
    internal int RVA;
    internal int Field;
    internal PESection TargetSection;
  }
  internal struct FileRow{
    internal int Flags;
    internal int Name;
    internal int HashValue;
  }
  internal struct GenericParamRow{
    internal int Number;
    internal int Flags;
    internal int Owner;
    internal int Name;
    internal Member GenericParameter;
  }
  internal struct GenericParamConstraintRow{
    internal int Param;
    internal int Constraint;
  }
  internal struct ImplMapRow{
    internal int MappingFlags;
    internal int MemberForwarded;
    internal int ImportName;
    internal int ImportScope;
  }
  internal struct InterfaceImplRow{
    internal int Class;
    internal int Interface;
  }
  internal struct ManifestResourceRow{
    internal int Offset;
    internal int Flags;
    internal int Name;
    internal int Implementation;
  }
  internal struct MemberRefRow{
    internal int Class;
    internal int Name;
    internal int Signature;
    internal Member Member;
    internal TypeNodeList VarargTypes;
  }
  internal struct MethodRow{
    internal int RVA;
    internal int ImplFlags;
    internal int Flags;
    internal int Name;
    internal int Signature;
    internal int ParamList;
    internal Method Method;
  }
  internal struct MethodImplRow{
    internal int Class;
    internal int MethodBody;
    internal int MethodDeclaration;
  }
  internal struct MethodPtrRow{
    internal int Method;
  }
  internal struct MethodSemanticsRow{
    internal int Semantics;
    internal int Method;
    internal int Association;
  }
  internal struct MethodSpecRow{
    internal int Method;
    internal int Instantiation;
    internal Method InstantiatedMethod;
  }
  internal struct ModuleRow{
    internal int Generation;
    internal int Name;
    internal int Mvid;
    internal int EncId;
    internal int EncBaseId;
  }
  internal struct ModuleRefRow{
    internal int Name;
#if FxCop
    internal ModuleNode Module;
#else
    internal Module Module;
#endif
  }
  internal struct NestedClassRow{
    internal int NestedClass;
    internal int EnclosingClass;
  }
  internal struct ParamRow{
    internal int Flags;
    internal int Sequence;
    internal int Name;
  }
  internal struct ParamPtrRow{
    internal int Param;
  }
  internal struct PropertyRow{
    internal int Flags;
    internal int Name;
    internal int Signature;
  }
  internal struct PropertyPtrRow{
    internal int Property;
  }
  internal struct PropertyMapRow{
    internal int Parent;
    internal int PropertyList;
  }
  internal struct StandAloneSigRow{
    internal int Signature;
  }
  internal struct TypeDefRow{
    internal int Flags;
    internal int Name;
    internal int Namespace;
    internal int Extends;
    internal int FieldList;
    internal int MethodList;
    internal TypeNode Type;
    internal Identifier NamespaceId;
    internal int NamespaceKey;
    internal int NameKey;
  }
  internal struct TypeRefRow{
    internal int ResolutionScope;
    internal int Name;
    internal int Namespace;
    internal TypeNode Type;
  }
  internal struct TypeSpecRow{
    internal int Signature;
    internal TypeNode Type;
  }
  [Serializable]
  public sealed class InvalidMetadataException : System.Exception{
    public InvalidMetadataException(){}
    public InvalidMetadataException(string message)
      : base(message){
    }
    public InvalidMetadataException(string message, Exception innerException)
      : base(message, innerException){
    }
    private InvalidMetadataException(SerializationInfo info, StreamingContext context)
      : base(info, context){
    }
  }

  internal class CLIHeader{
    internal int            cb;
    internal ushort         majorRuntimeVersion;
    internal ushort         minorRuntimeVersion;
    internal DirectoryEntry metaData;
    internal int            flags;
    internal int            entryPointToken;
    internal DirectoryEntry resources;
    internal DirectoryEntry strongNameSignature;
    internal DirectoryEntry codeManagerTable;
    internal DirectoryEntry vtableFixups;
    internal DirectoryEntry exportAddressTableJumps;

    internal CLIHeader(){
      this.cb = 72;
      this.majorRuntimeVersion = 2;
      this.minorRuntimeVersion = 5;
      // initialization provided by runtime
      //this.flags = 0;
      //this.entryPointToken = 0;
    }
  }
  internal struct DirectoryEntry{
    internal int virtualAddress;
    internal int size;
  }
  internal class MetadataHeader{
    internal int    signature;
    internal ushort majorVersion;
    internal ushort minorVersion;
    internal int    reserved;
    internal string versionString;
    internal int    flags;
    internal StreamHeader[] streamHeaders;
  }
  internal class NTHeader {
    internal int signature;
    internal ushort machine;
    internal ushort numberOfSections;
    internal int   timeDateStamp;
    internal int   pointerToSymbolTable;
    internal int   numberOfSymbols;
    internal ushort sizeOfOptionalHeader;
    internal ushort characteristics;
    internal ushort magic;
    internal byte  majorLinkerVersion;
    internal byte  minorLinkerVersion;
    internal int   sizeOfCode;
    internal int   sizeOfInitializedData;
    internal int   sizeOfUninitializedData;
    internal int   addressOfEntryPoint;
    internal int   baseOfCode;
    internal int   baseOfData;
    internal ulong imageBase;
    internal int   sectionAlignment;
    internal int   fileAlignment;
    internal ushort majorOperatingSystemVersion;
    internal ushort minorOperatingSystemVersion;
    internal ushort majorImageVersion;
    internal ushort minorImageVersion;
    internal ushort majorSubsystemVersion;
    internal ushort minorSubsystemVersion;
    internal int   win32VersionValue;
    internal int   sizeOfImage;
    internal int   sizeOfHeaders;
    internal int   checkSum;
    internal ushort subsystem;
    internal ushort dllCharacteristics;
    internal long   sizeOfStackReserve;
    internal long   sizeOfStackCommit;
    internal long   sizeOfHeapReserve;
    internal long   sizeOfHeapCommit;
    internal int   loaderFlags;
    internal int   numberOfDataDirectories;
    internal DirectoryEntry exportTable;
    internal DirectoryEntry importTable;
    internal DirectoryEntry resourceTable;
    internal DirectoryEntry exceptionTable;
    internal DirectoryEntry certificateTable;
    internal DirectoryEntry baseRelocationTable;
    internal DirectoryEntry debugTable;
    internal DirectoryEntry copyrightTable;
    internal DirectoryEntry globalPointerTable;
    internal DirectoryEntry threadLocalStorageTable;
    internal DirectoryEntry loadConfigTable;
    internal DirectoryEntry boundImportTable;
    internal DirectoryEntry importAddressTable;
    internal DirectoryEntry delayImportTable;
    internal DirectoryEntry cliHeaderTable;
    internal DirectoryEntry reserved;

    internal NTHeader(){
      this.signature = 0x00004550; /* "PE\0\0" */ 
      this.machine = 0x14c;
      this.sizeOfOptionalHeader = 224;
      //this.characteristics = 0x0002 | 0x0004 | 0x008 | 0x0100; //executable | no COFF line nums | no COFF symbols | 32-bit machine (as required by the standard)
      this.characteristics = 0x0002; //executable (as required by the Linker team).
      this.magic = 0x10B;
      this.majorLinkerVersion = 6;
      this.baseOfCode = 0x2000;
      this.imageBase = 0x400000; //TODO: make this settable
      this.sectionAlignment = 8192;
      this.fileAlignment = 512;
      this.majorOperatingSystemVersion = 4;
      this.majorSubsystemVersion = 4;
      this.dllCharacteristics = 0x400;
      this.sizeOfStackReserve = 1048576;
      this.sizeOfStackCommit = 4096;
      this.sizeOfHeapReserve = 1048576;
      this.sizeOfHeapCommit = 4096;
      this.numberOfDataDirectories = 16;

      // initialization provided by runtime
      //this.numberOfSections = 0;
      //this.timeDateStamp = 0;
      //this.pointerToSymbolTable = 0;
      //this.numberOfSymbols = 0;
      //this.minorLinkerVersion = 0;
      //this.sizeOfCode = 0;
      //this.sizeOfInitializedData = 0;
      //this.sizeOfUninitializedData = 0;
      //this.addressOfEntryPoint = 0;
      //this.baseOfData = 0;
      //this.minorOperatingSystemVersion = 0;
      //this.majorImageVersion = 0;
      //this.minorImageVersion = 0;
      //this.minorSubsystemVersion = 0;
      //this.win32VersionValue = 0;
      //this.sizeOfImage = 0;
      //this.sizeOfHeaders = 0;
      //this.checkSum = 0;
      //this.subsystem = 0;
      //this.loaderFlags = 0x0;
    }
  }
  internal struct SectionHeader{
    internal string name;
    internal int    virtualSize;
    internal int    virtualAddress;
    internal int    sizeOfRawData;
    internal int    pointerToRawData;
    internal int    pointerToRelocations;
    internal int    pointerToLinenumbers;
    internal ushort numberOfRelocations;
    internal ushort numberOfLinenumbers;
    internal int    characteristics;
  }
  internal class StreamHeader{
    internal int offset;
    internal int size;
    internal String name;
  }
  internal class TablesHeader{
    internal int  reserved;
    internal byte majorVersion;
    internal byte minorVersion;
    internal byte heapSizes;
    internal byte rowId;
    internal long maskValid;
    internal long maskSorted;
    internal int[] countArray;
  }
  internal enum TableIndices{
    Module               = 0x00,
    TypeRef              = 0x01,
    TypeDef              = 0x02,
    FieldPtr             = 0x03,
    Field                = 0x04,
    MethodPtr            = 0x05,
    Method               = 0x06,
    ParamPtr             = 0x07,
    Param                = 0x08,
    InterfaceImpl        = 0x09,
    MemberRef            = 0x0A,
    Constant             = 0x0B,
    CustomAttribute      = 0x0C,
    FieldMarshal         = 0x0D,
    DeclSecurity         = 0x0E,
    ClassLayout          = 0x0F,
    FieldLayout          = 0x10,
    StandAloneSig        = 0x11,
    EventMap             = 0x12,
    EventPtr             = 0x13,
    Event                = 0x14,
    PropertyMap          = 0x15,
    PropertyPtr          = 0x16,
    Property             = 0x17,
    MethodSemantics      = 0x18,
    MethodImpl           = 0x19,
    ModuleRef            = 0x1A,
    TypeSpec             = 0x1B,
    ImplMap              = 0x1C,
    FieldRva             = 0x1D,
    EncLog               = 0x1E,
    EncMap               = 0x1F,
    Assembly             = 0x20,
    AssemblyProcessor    = 0x21,
    AssemblyOS           = 0x22,
    AssemblyRef          = 0x23,
    AssemblyRefProcessor = 0x24,
    AssemblyRefOS        = 0x25,
    File                 = 0x26,
    ExportedType         = 0x27,
    ManifestResource     = 0x28,
    NestedClass          = 0x29,
    GenericParam         = 0x2a,
    MethodSpec           = 0x2b,
    GenericParamConstraint = 0x2c,
    Count
  }
  internal enum ElementType{
    End              = 0x00,
    Void             = 0x01,
    Boolean          = 0x02,
    Char             = 0x03,
    Int8             = 0x04,
    UInt8            = 0x05,
    Int16            = 0x06,
    UInt16           = 0x07,
    Int32            = 0x08,
    UInt32           = 0x09,
    Int64            = 0x0a,
    UInt64           = 0x0b,
    Single           = 0x0c,
    Double           = 0x0d,
    String           = 0x0e,
    Pointer          = 0x0f,
    Reference        = 0x10,
    ValueType        = 0x11,
    Class            = 0x12,
    TypeParameter    = 0x13,
    Array            = 0x14,
    GenericTypeInstance = 0x15,
    DynamicallyTypedReference   = 0x16,
    IntPtr           = 0x18,
    UIntPtr          = 0x19,
    FunctionPointer  = 0x1b,
    Object           = 0x1c,
    SzArray          = 0x1d,
    MethodParameter  = 0x1e,
    RequiredModifier = 0x1f,
    OptionalModifier = 0x20,
    Internal         = 0x21,
    Modifier         = 0x40,
    Sentinel         = 0x41,
    Pinned           = 0x45,
    Type             = 0x50,
    BoxedEnum        = 0x51,
    Enum             = 0x55
  }

  unsafe internal class MetadataReader : IDisposable{
#if !ROTOR
    private MemoryMappedFile memmap;
#endif
    readonly private MemoryCursor/*!*/ cursor;
    internal int entryPointToken;
    internal int fileAlignment;
    internal ulong baseAddress;
    internal long sizeOfStackReserve;
    internal ModuleKindFlags moduleKind;
    internal PEKindFlags peKind;
    internal bool TrackDebugData;
    private int mdOffset;
    private int resourcesOffset;
    private int win32ResourcesOffset;
    private SectionHeader[] sectionHeaders;
    //^ [SpecPublic]
    private StreamHeader identifierStringHeap;
    //^ [SpecPublic]
    private StreamHeader generalStringHeap;
    private StreamHeader blobHeap;
    //^ [SpecPublic]
    private StreamHeader guidHeap;
    private StreamHeader tables;
    internal TablesHeader tablesHeader;
    internal string targetRuntimeVersion;
    internal ushort dllCharacteristics;
    internal int linkerMajorVersion;
    internal int linkerMinorVersion;
    internal int metadataFormatMajorVersion;
    internal int metadataFormatMinorVersion;
    private int blobRefSize;
    private int constantParentRefSize;
    private int customAttributeParentRefSize;
    private int customAttributeConstructorRefSize;
    private int declSecurityParentRefSize;
    private int fieldMarshalParentRefSize;
    private int guidRefSize;
    private int hasSemanticRefSize;
    private int implementationRefSize;
    private int methodDefOrRefSize;
    private int memberRefParentSize;
    private int memberForwardedRefSize;
    private int typeDefOrRefOrSpecSize;
    private int typeDefOrMethodDefSize;
    private int resolutionScopeRefSize;
    private int stringRefSize;
    private int[] tableSize;
    private int[] tableRefSize;
    private int[] tableOffset;
    internal byte[] HashValue;

#if !ROTOR
    internal MetadataReader(string path){
      MemoryMappedFile memmap = this.memmap = new MemoryMappedFile(path);
      try {
        this.cursor = new MemoryCursor(memmap);
        //^ base();
        ReadHeader();
      } catch {
        this.Dispose();
        throw;
      }
    }
#endif
    
    internal MetadataReader(byte* buffer, int length){
      this.cursor = new MemoryCursor(buffer, length);
      //^ base();
      ReadHeader();
    }

    public void Dispose(){
#if !ROTOR
      if (this.memmap != null) this.memmap.Dispose();
      this.memmap = null;
#endif
      //this.cursor = null;
      this.sectionHeaders = null;
      this.identifierStringHeap = null;
      this.generalStringHeap = null;
      this.blobHeap = null;
      this.guidHeap = null;
      this.tables = null;
      this.tablesHeader = null;
      this.targetRuntimeVersion = null;
      this.tableSize = null;
      this.tableRefSize = null;
      this.tableOffset = null;
      this.HashValue = null;
    }

    private AssemblyRow[] assemblyTable;
    private AssemblyRefRow[] assemblyRefTable;
    private ClassLayoutRow[] classLayoutTable;
    private ConstantRow[] constantTable;
    private CustomAttributeRow[] customAttributeTable;
    private DeclSecurityRow[] declSecurityTable;
    private EventMapRow[] eventMapTable;
    private EventPtrRow[] eventPtrTable;
    private EventRow[] eventTable;
    private ExportedTypeRow[] exportedTypeTable;
    private FieldRow[] fieldTable;
    private FieldLayoutRow[] fieldLayoutTable;
    private FieldMarshalRow[] fieldMarshalTable;
    private FieldPtrRow[] fieldPtrTable;
    private FieldRvaRow[] fieldRvaTable;
    private FileRow[] fileTable;
    private GenericParamRow[] genericParamTable;
    private GenericParamConstraintRow[] genericParamConstraintTable;
    private ImplMapRow[] implMapTable;
    private InterfaceImplRow[] interfaceImplTable;
    private ManifestResourceRow[] manifestResourceTable;
    private MemberRefRow[] memberRefTable;
    private MethodRow[] methodTable;
    private MethodPtrRow[] methodPtrTable;
    private MethodImplRow[] methodImplTable;
    private MethodSemanticsRow[] methodSemanticsTable;
    private MethodSpecRow[] methodSpecTable;
    private ModuleRow[] moduleTable;
    private ModuleRefRow[] moduleRefTable;
    private NestedClassRow[] nestedClassTable;
    private ParamRow[] paramTable;
    private ParamPtrRow[] paramPtrTable;
    private PropertyRow[] propertyTable;
    private PropertyMapRow[] propertyMapTable;
    private PropertyPtrRow[] propertyPtrTable;
    private StandAloneSigRow[] standAloneSigTable;
    private TypeDefRow[] typeDefTable;
    private TypeRefRow[] typeRefTable;
    private TypeSpecRow[] typeSpecTable;

    internal AssemblyRow[]/*!*/ AssemblyTable{
      get{if (this.assemblyTable == null) this.ReadAssemblyTable(); return this.assemblyTable;}
    }
    internal AssemblyRefRow[]/*!*/ AssemblyRefTable {
      get{if (this.assemblyRefTable == null) this.ReadAssemblyRefTable(); return this.assemblyRefTable;}
    }
    internal ClassLayoutRow[]/*!*/ ClassLayoutTable {
      get{if (this.classLayoutTable == null) this.ReadClassLayoutTable(); return this.classLayoutTable;}
    }
    internal ConstantRow[]/*!*/ ConstantTable {
      get{if (this.constantTable == null) this.ReadConstantTable(); return this.constantTable;}
    }
    internal CustomAttributeRow[]/*!*/ CustomAttributeTable {
      get{if (this.customAttributeTable == null) this.ReadCustomAttributeTable(); return this.customAttributeTable;}
    }
    internal DeclSecurityRow[]/*!*/ DeclSecurityTable {
      get{if (this.declSecurityTable == null) this.ReadDeclSecurityTable(); return this.declSecurityTable;}
    }
    internal EventMapRow[]/*!*/ EventMapTable {
      get{if (this.eventMapTable == null) this.ReadEventMapTable(); return this.eventMapTable;}
    }
    internal EventPtrRow[]/*!*/ EventPtrTable {
      get{if (this.eventPtrTable == null) this.ReadEventPtrTable(); return this.eventPtrTable;}
    }
    internal EventRow[]/*!*/ EventTable {
      get{if (this.eventTable == null) this.ReadEventTable(); return this.eventTable;}
    }
    internal ExportedTypeRow[]/*!*/ ExportedTypeTable {
      get{if (this.exportedTypeTable == null) this.ReadExportedTypeTable(); return this.exportedTypeTable;}
    }
    internal FieldRow[]/*!*/ FieldTable {
      get{if (this.fieldTable == null) this.ReadFieldTable(); return this.fieldTable;}
    }
    internal FieldLayoutRow[]/*!*/ FieldLayoutTable {
      get{if (this.fieldLayoutTable == null) this.ReadFieldLayoutTable(); return this.fieldLayoutTable;}
    }
    internal FieldMarshalRow[]/*!*/ FieldMarshalTable {
      get{if (this.fieldMarshalTable == null) this.ReadFieldMarshalTable(); return this.fieldMarshalTable;}
    }
    internal FieldPtrRow[]/*!*/ FieldPtrTable {
      get{if (this.fieldPtrTable == null) this.ReadFieldPtrTable(); return this.fieldPtrTable;}
    }
    internal FieldRvaRow[]/*!*/ FieldRvaTable {
      get{if (this.fieldRvaTable == null) this.ReadFieldRvaTable(); return this.fieldRvaTable;}
    }
    internal FileRow[]/*!*/ FileTable {
      get{if (this.fileTable == null) this.ReadFileTable(); return this.fileTable;}
    }
    internal GenericParamRow[]/*!*/ GenericParamTable {
      get{if (this.genericParamTable == null) this.ReadGenericParamTable(); return this.genericParamTable;}
    }
    internal GenericParamConstraintRow[]/*!*/ GenericParamConstraintTable {
      get{if (this.genericParamConstraintTable == null) this.ReadGenericParamConstraintTable(); return this.genericParamConstraintTable;}
    }
    internal ImplMapRow[]/*!*/ ImplMapTable {
      get{if (this.implMapTable == null) this.ReadImplMapTable(); return this.implMapTable;}
    }
    internal InterfaceImplRow[]/*!*/ InterfaceImplTable {
      get{if (this.interfaceImplTable == null) this.ReadInterfaceImplTable(); return this.interfaceImplTable;}
    }
    internal ManifestResourceRow[]/*!*/ ManifestResourceTable {
      get{if (this.manifestResourceTable == null) this.ReadManifestResourceTable(); return this.manifestResourceTable;}
    }
    internal MemberRefRow[]/*!*/ MemberRefTable {
      get{if (this.memberRefTable == null) this.ReadMemberRefTable(); return this.memberRefTable;}
    }
    internal MethodRow[]/*!*/ MethodTable {
      get{if (this.methodTable == null) this.ReadMethodTable(); return this.methodTable;}
    }
    internal MethodImplRow[]/*!*/ MethodImplTable {
      get{if (this.methodImplTable == null) this.ReadMethodImplTable(); return this.methodImplTable;}
    }
    internal MethodPtrRow[]/*!*/ MethodPtrTable {
      get{if (this.methodPtrTable == null) this.ReadMethodPtrTable(); return this.methodPtrTable;}
    }
    internal MethodSemanticsRow[]/*!*/ MethodSemanticsTable {
      get{if (this.methodSemanticsTable == null) this.ReadMethodSemanticsTable(); return this.methodSemanticsTable;}
    }
    internal MethodSpecRow[]/*!*/ MethodSpecTable {
      get{if (this.methodSpecTable == null) this.ReadMethodSpecTable(); return this.methodSpecTable;}
    }
    internal ModuleRow[]/*!*/ ModuleTable {
      get{if (this.moduleTable == null) this.ReadModuleTable(); return this.moduleTable;}
    }
    internal ModuleRefRow[]/*!*/ ModuleRefTable {
      get{if (this.moduleRefTable == null) this.ReadModuleRefTable(); return this.moduleRefTable;}
    }
    internal NestedClassRow[]/*!*/ NestedClassTable {
      get{if (this.nestedClassTable == null) this.ReadNestedClassTable(); return this.nestedClassTable;}
    }
    internal ParamRow[]/*!*/ ParamTable {
      get{if (this.paramTable == null) this.ReadParamTable(); return this.paramTable;}
    }
    internal ParamPtrRow[]/*!*/ ParamPtrTable {
      get{if (this.paramPtrTable == null) this.ReadParamPtrTable(); return this.paramPtrTable;}
    }
    internal PropertyRow[]/*!*/ PropertyTable {
      get{if (this.propertyTable == null) this.ReadPropertyTable(); return this.propertyTable;}
    }
    internal PropertyMapRow[]/*!*/ PropertyMapTable {
      get{if (this.propertyMapTable == null) this.ReadPropertyMapTable(); return this.propertyMapTable;}
    }
    internal PropertyPtrRow[]/*!*/ PropertyPtrTable {
      get{if (this.propertyPtrTable == null) this.ReadPropertyPtrTable(); return this.propertyPtrTable;}
    }
    internal StandAloneSigRow[]/*!*/ StandAloneSigTable {
      get{if (this.standAloneSigTable == null) this.ReadStandAloneSigTable(); return this.standAloneSigTable;}
    }
    internal TypeDefRow[]/*!*/ TypeDefTable {
      get{if (this.typeDefTable == null) this.ReadTypeDefTable(); return this.typeDefTable;}
    }
    internal TypeRefRow[]/*!*/ TypeRefTable {
      get{if (this.typeRefTable == null) this.ReadTypeRefTable(); return this.typeRefTable;}
    }
    internal TypeSpecRow[]/*!*/ TypeSpecTable {
      get{if (this.typeSpecTable == null) this.ReadTypeSpecTable(); return this.typeSpecTable;}
    }

    internal void SetCurrentPosition(int pos){
      this.cursor.Position = pos;
    }
    internal void AlignTo32BitBoundary(){
      this.cursor.Align(4);
    }
    internal void Skip(int bytes){
      this.cursor.SkipByte(bytes);
    }
    internal byte[] emptyBlob;
    internal byte[]/*!*/ EmptyBlob
    {
      get
      {
        if (this.emptyBlob == null) { this.emptyBlob = new byte[0]; }
        return this.emptyBlob;
      }
    }
    internal byte[]/*!*/ GetBlob(int blobIndex) {
      // special case absence of blob. Index 0 denotes empty blob
      if (this.blobHeap == null && blobIndex == 0) return this.EmptyBlob;
      MemoryCursor c = this.cursor;
      c.Position = PositionOfBlob(blobIndex);
      return c.ReadBytes(c.ReadCompressedInt());
    }
    internal MemoryCursor/*!*/ GetBlobCursor(int blobIndex) {
      MemoryCursor c = this.cursor;
      c.Position = PositionOfBlob(blobIndex);
      c.ReadCompressedInt();
      return new MemoryCursor(c);
    }
    internal MemoryCursor/*!*/ GetBlobCursor(int blobIndex, out int blobLength) {
      MemoryCursor c = this.cursor;
      c.Position = PositionOfBlob(blobIndex);
      blobLength = c.ReadCompressedInt();
      return new MemoryCursor(c);
    }
    internal System.Guid GetGuid(int guidIndex)
      //^ requires this.guidHeap != null;
    {
      int guidOffset = guidIndex * 16;
      if (guidOffset < 16 || this.guidHeap.size < guidOffset)
        throw new System.ArgumentOutOfRangeException("guidIndex", ExceptionStrings.BadGuidHeapIndex);
      MemoryCursor c = this.cursor;
      c.Position = this.mdOffset+this.guidHeap.offset+guidOffset-16;
      return new System.Guid(c.ReadBytes(16));
    }
    internal Identifier/*!*/ GetIdentifier(int stringHeapIndex)
      //^ requires this.identifierStringHeap != null;
    {
      int position = this.mdOffset+this.identifierStringHeap.offset+stringHeapIndex;
      MemoryCursor c = this.cursor;
      return Identifier.For(c.GetBuffer(), position/*, c.KeepAlive*/);
    }
    internal byte GetMethodBodyHeaderByte(int RVA){
      MemoryCursor c = this.cursor;
      c.Position = this.RvaToOffset(RVA);
      return c.ReadByte();
    }
    internal MemoryCursor/*!*/ GetNewCursor() {
      return new MemoryCursor(this.cursor);
    }
    internal MemoryCursor/*!*/ GetNewCursor(int RVA, out PESection targetSection) {
      MemoryCursor c = new MemoryCursor(this.cursor);
      c.Position = this.RvaToOffset(RVA, out targetSection);
      return c;
    }
    internal byte GetByte(){
      MemoryCursor c = this.cursor;
      return c.ReadByte();
    }
    internal int GetCurrentPosition(){
      return this.cursor.Position;
    }
    internal int GetInt32(){
      MemoryCursor c = this.cursor;
      return c.ReadInt32();
    }
    internal short GetInt16(){
      MemoryCursor c = this.cursor;
      return c.ReadInt16();
    }
    internal ushort GetUInt16(){
      MemoryCursor c = this.cursor;
      return c.ReadUInt16();
    }
    internal int GetSignatureLength(int blobIndex){
      MemoryCursor c = this.cursor;
      c.Position = this.PositionOfBlob(blobIndex);
      return c.ReadCompressedInt();
    }
    internal string/*!*/ GetString(int stringHeapIndex)
      //^ requires this.identifierStringHeap != null;
    {
      if (stringHeapIndex < 0 || this.identifierStringHeap.size <= stringHeapIndex)
        throw new System.ArgumentOutOfRangeException("stringHeapIndex", ExceptionStrings.BadStringHeapIndex);
      MemoryCursor c = this.cursor;
      c.Position = this.mdOffset+this.identifierStringHeap.offset+stringHeapIndex;
      return c.ReadUTF8();
    }
    internal string/*!*/ GetUserString(int stringHeapIndex)
      //^ requires this.generalStringHeap != null;
    {
      if (stringHeapIndex < 0 || this.generalStringHeap.size <= stringHeapIndex)
        throw new System.ArgumentOutOfRangeException("stringHeapIndex", ExceptionStrings.BadUserStringHeapIndex);
      MemoryCursor c = this.cursor;
      c.Position = this.mdOffset+this.generalStringHeap.offset+stringHeapIndex;
      int strLength = c.ReadCompressedInt();
      return c.ReadUTF16(strLength/2);
    }
    internal string/*!*/ GetBlobString(int blobIndex) {
      MemoryCursor c = this.cursor;
      c.Position = this.PositionOfBlob(blobIndex);
      int blobLength = c.ReadCompressedInt();
      return c.ReadUTF16(blobLength/2);
    }
    internal object GetValueFromBlob(int type, int blobIndex){
      MemoryCursor c = this.cursor;
      c.Position = this.PositionOfBlob(blobIndex);
      int blobLength = c.ReadCompressedInt();
      switch((ElementType)type){
        case ElementType.Boolean: return c.ReadBoolean(); 
        case ElementType.Char: return (char)c.ReadUInt16(); 
        case ElementType.Double: return c.ReadDouble(); 
        case ElementType.Single: return c.ReadSingle(); 
        case ElementType.Int16: return c.ReadInt16(); 
        case ElementType.Int32: return c.ReadInt32(); 
        case ElementType.Int64: return c.ReadInt64(); 
        case ElementType.Int8: return c.ReadSByte(); 
        case ElementType.UInt16: return c.ReadUInt16(); 
        case ElementType.UInt32: return c.ReadUInt32(); 
        case ElementType.UInt64: return c.ReadUInt64(); 
        case ElementType.UInt8: return c.ReadByte(); 
        case ElementType.Class: return null;
        case ElementType.String: return c.ReadUTF16(blobLength/2);
      }
      throw new InvalidMetadataException(ExceptionStrings.UnknownConstantType);
    }
    internal byte[] GetResourceData(int resourceOffset){
      this.cursor.Position = this.resourcesOffset+resourceOffset;
      int length = this.cursor.ReadInt32(); 
      return this.cursor.ReadBytes(length);
    }
    private int PositionOfBlob(int blobIndex) 
      //^ requires this.blobHeap != null;
    {
      if (blobIndex < 0 || this.blobHeap.size <= blobIndex)
        throw new System.ArgumentOutOfRangeException("blobIndex", ExceptionStrings.BadBlobHeapIndex);
      return this.mdOffset+this.blobHeap.offset+blobIndex;
    }
    private void ReadHeader(){ //TODO: break up this method
      MemoryCursor c = this.cursor;
      c.Position = 0;

      ReadDOSHeader(c);
      NTHeader ntHeader = ReadNTHeader(c);
      this.dllCharacteristics = ntHeader.dllCharacteristics;
      this.linkerMajorVersion = ntHeader.majorLinkerVersion;
      this.linkerMinorVersion = ntHeader.minorLinkerVersion;
      this.fileAlignment = ntHeader.fileAlignment;
      this.baseAddress = ntHeader.imageBase;
      this.sizeOfStackReserve = ntHeader.sizeOfStackReserve;
      if ((ntHeader.characteristics & 0x2000) != 0)
        this.moduleKind = ModuleKindFlags.DynamicallyLinkedLibrary;
      else
        this.moduleKind = ntHeader.subsystem == 0x3 ? ModuleKindFlags.ConsoleApplication : ModuleKindFlags.WindowsApplication;
      
      int sectionCount = ntHeader.numberOfSections;
      SectionHeader[] sectionHeaders = this.sectionHeaders = new SectionHeader[sectionCount];
      int resourceSectionIndex = -1;
      for (int i = 0; i < sectionCount; i++){
        sectionHeaders[i] = ReadSectionHeader(c);
        if (sectionHeaders[i].name == ".rsrc") resourceSectionIndex = i;
      }
      if (resourceSectionIndex >= 0)
        this.win32ResourcesOffset = sectionHeaders[resourceSectionIndex].pointerToRawData;
      else
        this.win32ResourcesOffset = -1;

      DirectoryEntry de = ntHeader.cliHeaderTable;
      int cliHeaderOffset = this.RvaToOffset(de.virtualAddress);
      c.Position = cliHeaderOffset;

      CLIHeader cliHeader = ReadCLIHeader(c);
      this.entryPointToken = cliHeader.entryPointToken;
      if ((cliHeader.flags & 1) != 0)
        this.peKind = PEKindFlags.ILonly;
      if ((cliHeader.flags & 0x10) != 0)
        this.entryPointToken = 0; //Native entry point. Ignore.
      switch (ntHeader.machine){
        case 0x0200 : 
          this.peKind |= PEKindFlags.Requires64bits; 
          break;
        case 0x8664 : 
          this.peKind |= PEKindFlags.Requires64bits|PEKindFlags.AMD; 
          break;
        default:
          if (ntHeader.magic == 0x20B) //Optional header magic for PE32+
            this.peKind |= PEKindFlags.Requires64bits;
          else
          {
            if ((cliHeader.flags & 2) != 0)
              this.peKind |= PEKindFlags.Requires32bits;
            if ((cliHeader.flags & 0x00020000) != 0)
              this.peKind |= PEKindFlags.Prefers32bits;
          }
          break;
      }
      this.TrackDebugData = (cliHeader.flags & 0x10000) != 0;
      if (cliHeader.resources.size > 0)
        this.resourcesOffset = this.RvaToOffset(cliHeader.resources.virtualAddress);

      int snSize = cliHeader.strongNameSignature.size;
      if (snSize > 0){
        long hashOffset = this.RvaToOffset(cliHeader.strongNameSignature.virtualAddress);
        c.Position = (int)hashOffset;
        this.HashValue = c.ReadBytes(snSize);
        bool zeroHash = true;
        for (int i = 0; i < snSize; i++) if (this.HashValue[i] != 0) zeroHash = false;
        if (zeroHash) this.HashValue = null; //partially signed assembly
      }

      long mdOffset = this.mdOffset = this.RvaToOffset(cliHeader.metaData.virtualAddress);
      c.Position = (int)mdOffset;
      MetadataHeader mdHeader = ReadMetadataHeader(c);
      this.targetRuntimeVersion = mdHeader.versionString;

      foreach (StreamHeader sheader in mdHeader.streamHeaders){
        //^ assume sheader != null;
        switch (sheader.name){
          case "#Strings" : this.identifierStringHeap = sheader; continue;
          case "#US" : this.generalStringHeap = sheader; continue;
          case "#Blob" : this.blobHeap = sheader; continue;
          case "#GUID" : this.guidHeap = sheader; continue;
          case "#~" : this.tables = sheader; continue;
          case "#-" : this.tables = sheader; continue;
          default: continue;
        }
      }
      if (this.tables == null) throw new InvalidMetadataException(ExceptionStrings.NoMetadataStream);
      c.Position = (int)(mdOffset+this.tables.offset);
      TablesHeader tablesHeader = this.tablesHeader = ReadTablesHeader(c);
      this.metadataFormatMajorVersion = tablesHeader.majorVersion;
      this.metadataFormatMinorVersion = tablesHeader.minorVersion;

      int[] tableSize = this.tableSize = new int[(int)TableIndices.Count];
      int[] tableRefSize = this.tableRefSize = new int[(int)TableIndices.Count];
      long valid = tablesHeader.maskValid;
      int[] countArray = tablesHeader.countArray;
      //^ assume countArray != null;
      for (int i = 0, j = 0; i < (int)TableIndices.Count; i++){
        if (valid % 2 == 1){
          int m = tableSize[i] = countArray[j++];
          tableRefSize[i] = m < 0x10000 ? 2 : 4;
        }else
          tableRefSize[i] = 2;
        valid /= 2;
      }
      int blobRefSize = this.blobRefSize = ((tablesHeader.heapSizes & 0x04) == 0 ? 2 : 4);
      int constantParentRefSize = this.constantParentRefSize = 
        tableSize[(int)TableIndices.Param] < 0x4000 && 
        tableSize[(int)TableIndices.Field] < 0x4000 && 
        tableSize[(int)TableIndices.Property] < 0x4000 ? 2 : 4;
      int customAttributeParentRefSize = 0;
      if (this.metadataFormatMajorVersion > 1 || this.metadataFormatMinorVersion > 0){
        customAttributeParentRefSize = this.customAttributeParentRefSize =
          tableSize[(int)TableIndices.Method] < 0x0800 &&
          tableSize[(int)TableIndices.Field] < 0x0800 &&
          tableSize[(int)TableIndices.TypeRef] < 0x0800 &&
          tableSize[(int)TableIndices.TypeDef] < 0x0800 &&
          tableSize[(int)TableIndices.Param] < 0x0800 &&
          tableSize[(int)TableIndices.InterfaceImpl] < 0x0800 &&
          tableSize[(int)TableIndices.MemberRef] < 0x0800 &&
          tableSize[(int)TableIndices.Module] < 0x0800 &&
          tableSize[(int)TableIndices.DeclSecurity] < 0x0800 &&
          tableSize[(int)TableIndices.Property] < 0x0800 &&
          tableSize[(int)TableIndices.Event] < 0x0800 &&
          tableSize[(int)TableIndices.StandAloneSig] < 0x0800 &&
          tableSize[(int)TableIndices.ModuleRef] < 0x0800 &&
          tableSize[(int)TableIndices.TypeSpec] < 0x0800 &&
          tableSize[(int)TableIndices.Assembly] < 0x0800 &&
          tableSize[(int)TableIndices.File] < 0x0800 &&
          tableSize[(int)TableIndices.ExportedType] < 0x0800 &&
          tableSize[(int)TableIndices.ManifestResource] < 0x0800 &&
          tableSize[(int)TableIndices.GenericParam] < 0x0800 &&
          tableSize[(int)TableIndices.MethodSpec] < 0x0800 &&
          tableSize[(int)TableIndices.GenericParamConstraint] < 0x0800 ? 2 : 4;
      }else{
        customAttributeParentRefSize = this.customAttributeParentRefSize =
          tableSize[(int)TableIndices.Method] < 0x0800 &&
          tableSize[(int)TableIndices.Field] < 0x0800 &&
          tableSize[(int)TableIndices.TypeRef] < 0x0800 &&
          tableSize[(int)TableIndices.TypeDef] < 0x0800 &&
          tableSize[(int)TableIndices.Param] < 0x0800 &&
          tableSize[(int)TableIndices.InterfaceImpl] < 0x0800 &&
          tableSize[(int)TableIndices.MemberRef] < 0x0800 &&
          tableSize[(int)TableIndices.Module] < 0x0800 &&
          tableSize[(int)TableIndices.DeclSecurity] < 0x0800 &&
          tableSize[(int)TableIndices.Property] < 0x0800 &&
          tableSize[(int)TableIndices.Event] < 0x0800 &&
          tableSize[(int)TableIndices.StandAloneSig] < 0x0800 &&
          tableSize[(int)TableIndices.ModuleRef] < 0x0800 &&
          tableSize[(int)TableIndices.TypeSpec] < 0x0800 &&
          tableSize[(int)TableIndices.Assembly] < 0x0800 &&
          tableSize[(int)TableIndices.File] < 0x0800 &&
          tableSize[(int)TableIndices.ExportedType] < 0x0800 &&
          tableSize[(int)TableIndices.ManifestResource] < 0x0800 ? 2 : 4;
      }
      int customAttributeConstructorRefSize = this.customAttributeConstructorRefSize =
        tableSize[(int)TableIndices.Method] < 0x2000 &&
        tableSize[(int)TableIndices.MemberRef] < 0x2000 ? 2 : 4;
      int declSecurityParentRefSize = this.declSecurityParentRefSize = 
        tableSize[(int)TableIndices.TypeDef] < 0x4000 && 
        tableSize[(int)TableIndices.Method] < 0x4000 && 
        tableSize[(int)TableIndices.Assembly] < 0x4000 ? 2 : 4;
      int fieldMarshalParentRefSize = this.fieldMarshalParentRefSize = 
        tableSize[(int)TableIndices.Field] < 0x8000 && 
        tableSize[(int)TableIndices.Param] < 0x8000 ? 2 : 4;
      int guidRefSize = this.guidRefSize = ((tablesHeader.heapSizes & 0x02) == 0 ? 2 : 4);
      int hasSemanticRefSize = this.hasSemanticRefSize = 
        tableSize[(int)TableIndices.Event] < 0x8000 && 
        tableSize[(int)TableIndices.Property] < 0x8000 ? 2 : 4;
      int implementationRefSize = this.implementationRefSize = 
        tableSize[(int)TableIndices.File] < 0x4000 && 
        tableSize[(int)TableIndices.AssemblyRef] < 0x4000 && 
        tableSize[(int)TableIndices.ExportedType] < 0x4000 ? 2 : 4;
      int methodDefOrRefSize = this.methodDefOrRefSize = 
        tableSize[(int)TableIndices.Method] < 0x8000 && 
        tableSize[(int)TableIndices.MemberRef] < 0x8000 ? 2 : 4;
      int memberRefParentSize = this.memberRefParentSize =
        tableSize[(int)TableIndices.TypeDef] < 0x2000 &&
        tableSize[(int)TableIndices.TypeRef] < 0x2000 &&
        tableSize[(int)TableIndices.ModuleRef] < 0x2000 &&
        tableSize[(int)TableIndices.Method] < 0x2000 &&
        tableSize[(int)TableIndices.TypeSpec] < 0x2000 ? 2 : 4;
      int memberForwardedRefSize = this.memberForwardedRefSize = 
        tableSize[(int)TableIndices.Field] < 0x8000 && 
        tableSize[(int)TableIndices.Method] < 0x8000 ? 2 : 4;
      int typeDefOrMethodDefSize = this.typeDefOrMethodDefSize =
        tableSize[(int)TableIndices.TypeDef] < 0x8000 &&
        tableSize[(int)TableIndices.Method] < 0x8000 ? 2 : 4;
      int typeDefOrRefOrSpecSize = this.typeDefOrRefOrSpecSize = 
        tableSize[(int)TableIndices.TypeDef] < 0x4000 && 
        tableSize[(int)TableIndices.TypeRef] < 0x4000 && 
        tableSize[(int)TableIndices.TypeSpec] < 0x4000 ? 2 : 4;
      int resolutionScopeRefSize = this.resolutionScopeRefSize =
        tableSize[(int)TableIndices.Module] < 0x4000 &&
        tableSize[(int)TableIndices.ModuleRef] < 0x4000 &&
        tableSize[(int)TableIndices.AssemblyRef] < 0x4000 &&
        tableSize[(int)TableIndices.TypeRef] < 0x4000 ? 2 : 4;
      int stringRefSize = this.stringRefSize = ((tablesHeader.heapSizes & 0x01) == 0 ? 2 : 4);

      int[] tableOffset = this.tableOffset = new int[(int)TableIndices.Count];
      int offset = this.mdOffset + this.tables.offset + 24 + countArray.Length*4;
      for (int i = 0; i < (int)TableIndices.Count; i++){
        int m = tableSize[i];
        if (m == 0) continue;
        tableOffset[i] = offset;
        switch((TableIndices)i){
          case TableIndices.Module : offset += m * (2 + stringRefSize + 3*guidRefSize); break;
          case TableIndices.TypeRef : offset += m * (resolutionScopeRefSize + 2*stringRefSize); break;
          case TableIndices.TypeDef : offset += m * (4 + 2*stringRefSize + typeDefOrRefOrSpecSize + tableRefSize[(int)TableIndices.Field] + tableRefSize[(int)TableIndices.Method]); break;
          case TableIndices.FieldPtr: offset += m * (tableRefSize[(int)TableIndices.Field]); break;
          case TableIndices.Field : offset += m * (2 + stringRefSize + blobRefSize); break;
          case TableIndices.MethodPtr : offset += m * (tableRefSize[(int)TableIndices.Method]); break;
          case TableIndices.Method : offset += m * (8 + stringRefSize + blobRefSize + tableRefSize[(int)TableIndices.Param]); break;
          case TableIndices.ParamPtr: offset += m * (tableRefSize[(int)TableIndices.Param]); break;
          case TableIndices.Param : offset += m * (4 + stringRefSize); break;
          case TableIndices.InterfaceImpl : offset += m * (tableRefSize[(int)TableIndices.TypeDef]+typeDefOrRefOrSpecSize); break;
          case TableIndices.MemberRef : offset += m * (memberRefParentSize + stringRefSize + blobRefSize); break;
          case TableIndices.Constant : offset += m * (2 + constantParentRefSize + blobRefSize); break;
          case TableIndices.CustomAttribute : offset += m * (customAttributeParentRefSize + customAttributeConstructorRefSize + blobRefSize); break;
          case TableIndices.FieldMarshal : offset += m * (fieldMarshalParentRefSize + blobRefSize); break;
          case TableIndices.DeclSecurity : offset += m * (2 + declSecurityParentRefSize + blobRefSize); break;
          case TableIndices.ClassLayout : offset += m * (6 + tableRefSize[(int)TableIndices.TypeDef]); break;
          case TableIndices.FieldLayout : offset += m * (4 + tableRefSize[(int)TableIndices.Field]); break;
          case TableIndices.StandAloneSig : offset += m * (blobRefSize); break;
          case TableIndices.EventMap : offset += m * (tableRefSize[(int)TableIndices.TypeDef] + tableRefSize[(int)TableIndices.Event]); break;
          case TableIndices.EventPtr: offset += m * (tableRefSize[(int)TableIndices.Event]); break;
          case TableIndices.Event : offset += m * (2 + stringRefSize + typeDefOrRefOrSpecSize); break;
          case TableIndices.PropertyMap : offset += m * (tableRefSize[(int)TableIndices.TypeDef] + tableRefSize[(int)TableIndices.Property]); break;
          case TableIndices.PropertyPtr: offset += m * (tableRefSize[(int)TableIndices.Property]); break;
          case TableIndices.Property : offset += m * (2 + stringRefSize + blobRefSize); break;
          case TableIndices.MethodSemantics : offset += m * (2 + tableRefSize[(int)TableIndices.Method] + hasSemanticRefSize); break;
          case TableIndices.MethodImpl : offset += m * (tableRefSize[(int)TableIndices.TypeDef] + 2*methodDefOrRefSize); break;
          case TableIndices.ModuleRef : offset += m * (stringRefSize); break;
          case TableIndices.TypeSpec : offset += m * (blobRefSize); break;
          case TableIndices.ImplMap : offset += m * (2 + memberForwardedRefSize + stringRefSize + tableRefSize[(int)TableIndices.ModuleRef]); break;
          case TableIndices.FieldRva : offset += m * (4 + tableRefSize[(int)TableIndices.Field]); break;
          case TableIndices.EncLog: throw new InvalidMetadataException(ExceptionStrings.ENCLogTableEncountered);
          case TableIndices.EncMap: throw new InvalidMetadataException(ExceptionStrings.ENCMapTableEncountered);
          case TableIndices.Assembly : offset += m * (16 + blobRefSize + 2*stringRefSize); break;
          case TableIndices.AssemblyProcessor : offset += m * (4); break;
          case TableIndices.AssemblyOS : offset += m * (12); break;
          case TableIndices.AssemblyRef : offset += m * (12 + 2*blobRefSize + 2*stringRefSize); break;
          case TableIndices.AssemblyRefProcessor : offset += m * (4 + tableRefSize[(int)TableIndices.AssemblyRef]); break;
          case TableIndices.AssemblyRefOS : offset += m * (12 + tableRefSize[(int)TableIndices.AssemblyRef]); break;
          case TableIndices.File : offset += m * (4 + stringRefSize + blobRefSize); break;
          case TableIndices.ExportedType : offset += m * (8 + 2*stringRefSize + implementationRefSize); break;
          case TableIndices.ManifestResource : offset += m * (8 + stringRefSize + implementationRefSize); break;
          case TableIndices.NestedClass : offset += m * (2*tableRefSize[(int)TableIndices.TypeDef]); break;
          case TableIndices.GenericParam: 
            if (this.metadataFormatMajorVersion == 1 && this.metadataFormatMinorVersion == 0)
              offset += m * (6 + typeDefOrMethodDefSize + stringRefSize + typeDefOrRefOrSpecSize);
            else if (this.metadataFormatMajorVersion == 1 && this.metadataFormatMinorVersion == 1)
              offset += m * (4 + typeDefOrMethodDefSize + stringRefSize + typeDefOrRefOrSpecSize);
            else
              offset += m * (4 + typeDefOrMethodDefSize + stringRefSize);
            break;
          case TableIndices.MethodSpec: offset += m * (methodDefOrRefSize + blobRefSize); break;
          case TableIndices.GenericParamConstraint: offset += m * (tableRefSize[(int)TableIndices.GenericParam] + typeDefOrRefOrSpecSize); break;
          default: throw new InvalidMetadataException(ExceptionStrings.UnsupportedTableEncountered);
        }
      }
    }
    internal Win32ResourceList ReadWin32Resources(){
      Win32ResourceList rs = new Win32ResourceList();
      int startPos = this.win32ResourcesOffset;
      if (startPos < 0) return rs;
      MemoryCursor c = this.cursor;
      c.Position = startPos;
      int sizeOfTypeDirectory = ReadWin32ResourceDirectoryHeader(c);
      for (int i = 0; i < sizeOfTypeDirectory; i++){
        string TypeName = null;
        int TypeID = c.ReadInt32();
        if (TypeID < 0){
          MemoryCursor nac = new MemoryCursor(c);
          nac.Position = startPos+(TypeID&0x7FFFFFFF);
          int strLength = nac.ReadUInt16();
          TypeName = nac.ReadUTF16(strLength);
        }
        int offset = c.ReadInt32();
        if (offset >= 0)
          rs.Add(this.ReadWin32ResourceDataEntry(c, startPos+offset, TypeName, TypeID, null, 0, 0));
        else{
          MemoryCursor nc = new MemoryCursor(c);
          nc.Position = startPos+(offset&0x7FFFFFFF);
          int sizeOfNameDirectory = ReadWin32ResourceDirectoryHeader(nc);
          for (int j = 0; j < sizeOfNameDirectory; j++){
            string Name = null;
            int ID = nc.ReadInt32();
            if (ID < 0){
              MemoryCursor nac = new MemoryCursor(c);
              int strLength = nac.ReadUInt16();
              Name = nac.ReadUTF16(strLength);
            }
            offset = nc.ReadInt32();
            if (offset >= 0)
              rs.Add(this.ReadWin32ResourceDataEntry(c, startPos+offset, TypeName, TypeID, Name, ID, 0));
            else{
              MemoryCursor lc = new MemoryCursor(c);
              lc.Position = startPos+(offset&0x7FFFFFFF);
              int sizeOfLanguageDirectory = ReadWin32ResourceDirectoryHeader(lc);
              for (int k = 0; k < sizeOfLanguageDirectory; k++){
                int LanguageID = lc.ReadInt32();
                offset = lc.ReadInt32();
                rs.Add(this.ReadWin32ResourceDataEntry(c, startPos+offset, TypeName, TypeID, Name, ID, LanguageID));
              }
            }
          }
        }
      }
      return rs;
    }
    private static int ReadWin32ResourceDirectoryHeader(MemoryCursor/*!*/ c) {
      c.ReadInt32(); //Characteristics
      c.ReadInt32(); //TimeDate stamp
      c.ReadInt32(); //Version
      int numberOfNamedEntries = c.ReadUInt16();
      int numberOfIdEntries = c.ReadUInt16();
      return numberOfNamedEntries+numberOfIdEntries;
    }
    private Win32Resource ReadWin32ResourceDataEntry(MemoryCursor/*!*/ c, int position, 
      string TypeName, int TypeID, string Name, int ID, int LanguageID){
      Win32Resource rsrc = new Win32Resource();
      rsrc.TypeName = TypeName;
      rsrc.TypeId = TypeID;
      rsrc.Name = Name;
      rsrc.Id = ID;
      rsrc.LanguageId = LanguageID;
      c = new MemoryCursor(c);
      c.Position = position;
      int dataRVA = c.ReadInt32();
      int dataSize = c.ReadInt32();
      rsrc.CodePage = c.ReadInt32();
      c.Position = this.RvaToOffset(dataRVA);
      rsrc.Data = c.ReadBytes(dataSize);
      return rsrc;
    }
    private void ReadAssemblyTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.Assembly];
      AssemblyRow[] result = this.assemblyTable = new AssemblyRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.Assembly];
      for (int i = 0; i < n; i++){
        AssemblyRow row;
        row.HashAlgId = c.ReadInt32();
        row.MajorVersion = c.ReadUInt16();
        row.MinorVersion = c.ReadUInt16();
        row.BuildNumber = c.ReadUInt16();
        row.RevisionNumber = c.ReadUInt16();
        row.Flags = c.ReadInt32();
        row.PublicKey = c.ReadReference(this.blobRefSize);
        row.Name = c.ReadReference(this.stringRefSize);
        row.Culture = c.ReadReference(this.stringRefSize);
        result[i] = row;
      }
    }
    private void ReadAssemblyRefTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.AssemblyRef];
      AssemblyRefRow[] result = this.assemblyRefTable = new AssemblyRefRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.AssemblyRef];
      for (int i = 0; i < n; i++){
        AssemblyRefRow row;
        row.MajorVersion = c.ReadUInt16();
        row.MinorVersion = c.ReadUInt16();
        row.BuildNumber = c.ReadUInt16();
        row.RevisionNumber = c.ReadUInt16();
        row.Flags = c.ReadInt32();
        row.PublicKeyOrToken = c.ReadReference(this.blobRefSize);
        row.Name = c.ReadReference(this.stringRefSize);
        row.Culture = c.ReadReference(this.stringRefSize);
        row.HashValue = c.ReadReference(this.blobRefSize);
        row.AssemblyReference = null;
        result[i] = row;
      }
    }
    private void ReadClassLayoutTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.ClassLayout];
      ClassLayoutRow[] result = this.classLayoutTable = new ClassLayoutRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.ClassLayout];
      for (int i = 0; i < n; i++){
        ClassLayoutRow row;
        row.PackingSize = c.ReadUInt16();
        row.ClassSize = c.ReadInt32();
        row.Parent = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]);
        result[i] = row;
      }
    }
    private void ReadConstantTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.Constant];
      ConstantRow[] result = this.constantTable = new ConstantRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.Constant];
      for (int i = 0; i < n; i++){
        ConstantRow row;
        row.Type = c.ReadByte();
        c.ReadByte();
        row.Parent = c.ReadReference(this.constantParentRefSize);
        row.Value = c.ReadReference(this.blobRefSize);
        result[i] = row;
      }
    }
    private void ReadCustomAttributeTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.CustomAttribute];
      CustomAttributeRow[] result = this.customAttributeTable = new CustomAttributeRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.CustomAttribute];
      for (int i = 0; i < n; i++){
        CustomAttributeRow row;
        row.Parent = c.ReadReference(this.customAttributeParentRefSize);
        row.Constructor = c.ReadReference(this.customAttributeConstructorRefSize);
        row.Value = c.ReadReference(this.blobRefSize);
        result[i] = row;
      }
    }
    private void ReadDeclSecurityTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.DeclSecurity];
      DeclSecurityRow[] result = this.declSecurityTable = new DeclSecurityRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.DeclSecurity];
      for (int i = 0; i < n; i++){
        DeclSecurityRow row;
        row.Action = c.ReadUInt16();
        row.Parent = c.ReadReference(this.declSecurityParentRefSize);
        row.PermissionSet = c.ReadReference(this.blobRefSize);
        result[i] = row;
      }
    }
    private void ReadEventMapTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.EventMap];
      EventMapRow[] result = this.eventMapTable = new EventMapRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.EventMap];
      for (int i = 0; i < n; i++){
        EventMapRow row;
        row.Parent = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]);
        row.EventList = c.ReadReference(this.tableRefSize[(int)TableIndices.Event]);
        result[i] = row;
      }
    }
    private void ReadEventPtrTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.EventPtr];
      EventPtrRow[] result = this.eventPtrTable = new EventPtrRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.EventPtr];
      for (int i = 0; i < n; i++){
        EventPtrRow row;
        row.Event = c.ReadReference(this.tableRefSize[(int)TableIndices.Event]);
        result[i] = row;
      }
    }
    private void ReadEventTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.Event];
      EventRow[] result = this.eventTable = new EventRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.Event];
      for (int i = 0; i < n; i++){
        EventRow row;
        row.Flags = c.ReadUInt16();
        row.Name = c.ReadReference(this.stringRefSize);
        row.EventType = c.ReadReference(this.typeDefOrRefOrSpecSize);
        result[i] = row;
      }
    }
    private void ReadExportedTypeTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.ExportedType];
      ExportedTypeRow[] result = this.exportedTypeTable = new ExportedTypeRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.ExportedType];
      for (int i = 0; i < n; i++){
        ExportedTypeRow row;
        row.Flags = c.ReadInt32();
        row.TypeDefId = c.ReadInt32();
        row.TypeName = c.ReadReference(this.stringRefSize);
        row.TypeNamespace = c.ReadReference(this.stringRefSize);
        row.Implementation = c.ReadReference(this.implementationRefSize);
        result[i] = row;
      }
    }
    private void ReadFieldTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.Field];
      FieldRow[] result = this.fieldTable = new FieldRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.Field];
      for (int i = 0; i < n; i++){
        FieldRow row;
        row.Flags = c.ReadUInt16();
        row.Name = c.ReadReference(this.stringRefSize);
        row.Signature = c.ReadReference(this.blobRefSize);
        row.Field = null;
        result[i] = row;
      }
    }
    private void ReadFieldLayoutTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.FieldLayout];
      FieldLayoutRow[] result = this.fieldLayoutTable = new FieldLayoutRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.FieldLayout];
      for (int i = 0; i < n; i++){
        FieldLayoutRow row;
        row.Offset = c.ReadInt32();
        row.Field = c.ReadReference(this.tableRefSize[(int)TableIndices.Field]);
        result[i] = row;
      }
    }
    private void ReadFieldMarshalTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.FieldMarshal];
      FieldMarshalRow[] result = this.fieldMarshalTable = new FieldMarshalRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.FieldMarshal];
      for (int i = 0; i < n; i++){
        FieldMarshalRow row;
        row.Parent = c.ReadReference(this.fieldMarshalParentRefSize);
        row.NativeType = c.ReadReference(this.blobRefSize);
        result[i] = row;
      }
    }
    private void ReadFieldPtrTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.FieldPtr];
      FieldPtrRow[] result = this.fieldPtrTable = new FieldPtrRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.FieldPtr];
      for (int i = 0; i < n; i++){
        FieldPtrRow row;
        row.Field = c.ReadReference(this.tableRefSize[(int)TableIndices.Field]);
        result[i] = row;
      }
    }
    private void ReadFieldRvaTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.FieldRva];
      FieldRvaRow[] result = this.fieldRvaTable = new FieldRvaRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.FieldRva];
      for (int i = 0; i < n; i++){
        FieldRvaRow row;
        row.RVA = c.ReadInt32();
        row.Field = c.ReadReference(this.tableRefSize[(int)TableIndices.Field]);
        row.TargetSection = 0; //Ignored on reading
        result[i] = row;
      }
    }
    private void ReadFileTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.File];
      FileRow[] result = this.fileTable = new FileRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.File];
      for (int i = 0; i < n; i++){
        FileRow row;
        row.Flags = c.ReadInt32();
        row.Name = c.ReadReference(this.stringRefSize);
        row.HashValue = c.ReadReference(this.blobRefSize);
        result[i] = row;
      }
    }
    private void ReadGenericParamTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.GenericParam];
      GenericParamRow[] result = this.genericParamTable = new GenericParamRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.GenericParam];
      bool reallyOldGenericsFileFormat = this.metadataFormatMajorVersion == 1 && this.metadataFormatMinorVersion == 0;
      bool oldGenericsFileFormat = this.metadataFormatMajorVersion == 1 && this.metadataFormatMinorVersion == 1;
      for (int i = 0; i < n; i++){
        GenericParamRow row;
        row.Number = c.ReadUInt16();
        row.Flags = c.ReadUInt16();
        row.Owner = c.ReadReference(this.typeDefOrMethodDefSize);
        row.Name = c.ReadReference(this.stringRefSize);
        row.GenericParameter = null;
        if (oldGenericsFileFormat) c.ReadReference(this.typeDefOrRefOrSpecSize);
        if (reallyOldGenericsFileFormat) c.ReadInt16();
        result[i] = row;
      }
    }
    private void ReadGenericParamConstraintTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.GenericParamConstraint];
      GenericParamConstraintRow[] result = this.genericParamConstraintTable = new GenericParamConstraintRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.GenericParamConstraint];
      for (int i = 0; i < n; i++){
        GenericParamConstraintRow row;
        row.Param = c.ReadReference(this.tableRefSize[(int)TableIndices.GenericParam]);
        row.Constraint = c.ReadReference(this.typeDefOrRefOrSpecSize);
        result[i] = row;
      }
    }
    private void ReadImplMapTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.ImplMap];
      ImplMapRow[] result = this.implMapTable = new ImplMapRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.ImplMap];
      for (int i = 0; i < n; i++){
        ImplMapRow row;
        row.MappingFlags = c.ReadUInt16();
        row.MemberForwarded = c.ReadReference(this.memberForwardedRefSize);
        row.ImportName = c.ReadReference(this.stringRefSize);
        row.ImportScope = c.ReadReference(this.tableRefSize[(int)TableIndices.ModuleRef]);
        result[i] = row;
      }
    }
    private void ReadInterfaceImplTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.InterfaceImpl];
      InterfaceImplRow[] result = this.interfaceImplTable = new InterfaceImplRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.InterfaceImpl];
      for (int i = 0; i < n; i++){
        InterfaceImplRow row;
        row.Class = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]);
        row.Interface = c.ReadReference(this.typeDefOrRefOrSpecSize);
        result[i] = row;
      }
    }
    private void ReadManifestResourceTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.ManifestResource];
      ManifestResourceRow[] result = this.manifestResourceTable = new ManifestResourceRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.ManifestResource];
      for (int i = 0; i < n; i++){
        ManifestResourceRow row;
        row.Offset = c.ReadInt32();
        row.Flags = c.ReadInt32(); 
        row.Name = c.ReadReference(this.stringRefSize);
        row.Implementation = c.ReadReference(this.implementationRefSize);
        result[i] = row;
      }
    }
    private void ReadMemberRefTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.MemberRef];
      MemberRefRow[] result = this.memberRefTable = new MemberRefRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.MemberRef];
      for (int i = 0; i < n; i++){
        MemberRefRow row;
        row.Class = c.ReadReference(this.memberRefParentSize);
        row.Name = c.ReadReference(this.stringRefSize);
        row.Signature = c.ReadReference(this.blobRefSize);
        row.Member = null;
        row.VarargTypes = null;
        result[i] = row;
      }
    }
    private void ReadMethodTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.Method];
      MethodRow[] result = this.methodTable = new MethodRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.Method];
      for (int i = 0; i < n; i++){
        MethodRow row;
        row.RVA = c.ReadInt32();
        row.ImplFlags = c.ReadUInt16();
        row.Flags = c.ReadUInt16();
        row.Name = c.ReadReference(this.stringRefSize);
        row.Signature = c.ReadReference(this.blobRefSize);
        row.ParamList = c.ReadReference(this.tableRefSize[(int)TableIndices.Param]);
        row.Method = null;
        result[i] = row;
      }
    }
    private void ReadMethodImplTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.MethodImpl];
      MethodImplRow[] result = this.methodImplTable = new MethodImplRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.MethodImpl];
      for (int i = 0; i < n; i++){
        MethodImplRow row;
        row.Class = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]);
        row.MethodBody = c.ReadReference(this.methodDefOrRefSize);
        row.MethodDeclaration = c.ReadReference(this.methodDefOrRefSize);
        result[i] = row;
      }
    }
    private void ReadMethodPtrTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.MethodPtr];
      MethodPtrRow[] result = this.methodPtrTable = new MethodPtrRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.MethodPtr];
      for (int i = 0; i < n; i++){
        MethodPtrRow row;
        row.Method = c.ReadReference(this.tableRefSize[(int)TableIndices.Method]);
        result[i] = row;
      }
    }
    private void ReadMethodSemanticsTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.MethodSemantics];
      MethodSemanticsRow[] result = this.methodSemanticsTable = new MethodSemanticsRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.MethodSemantics];
      for (int i = 0; i < n; i++){
        MethodSemanticsRow row;
        row.Semantics = c.ReadUInt16();
        row.Method = c.ReadReference(this.tableRefSize[(int)TableIndices.Method]);
        row.Association = c.ReadReference(this.hasSemanticRefSize);
        result[i] = row;
      }
    }
    private void ReadMethodSpecTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.MethodSpec];
      MethodSpecRow[] result = this.methodSpecTable = new MethodSpecRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.MethodSpec];
      for (int i = 0; i < n; i++){
        MethodSpecRow row;
        row.Method = c.ReadReference(this.methodDefOrRefSize);
        row.Instantiation = c.ReadReference(this.blobRefSize);
        row.InstantiatedMethod = null;
        result[i] = row;
      }
    }
    private void ReadModuleTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.Module];
      ModuleRow[] result = this.moduleTable = new ModuleRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.Module];
      for (int i = 0; i < n; i++){
        ModuleRow row;
        row.Generation = c.ReadUInt16();
        row.Name = c.ReadReference(this.stringRefSize);
        row.Mvid = c.ReadReference(this.guidRefSize);
        row.EncId = c.ReadReference(this.guidRefSize);
        row.EncBaseId = c.ReadReference(this.guidRefSize);
        result[i] = row;
      }
    }
    private void ReadModuleRefTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.ModuleRef];
      ModuleRefRow[] result = this.moduleRefTable = new ModuleRefRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.ModuleRef];
      for (int i = 0; i < n; i++){
        ModuleRefRow row;
        row.Name = c.ReadReference(this.stringRefSize);
        row.Module = null;
        result[i] = row;
      }
    }
    private void ReadNestedClassTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.NestedClass];
      NestedClassRow[] result = this.nestedClassTable = new NestedClassRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.NestedClass];
      for (int i = 0; i < n; i++){
        NestedClassRow row;
        row.NestedClass = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]);
        row.EnclosingClass = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]);
        result[i] = row;
      }
    }
    private void ReadParamTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.Param];
      ParamRow[] result = this.paramTable = new ParamRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.Param];
      for (int i = 0; i < n; i++){
        ParamRow row;
        row.Flags = c.ReadUInt16();
        row.Sequence = c.ReadUInt16();
        row.Name = c.ReadReference(this.stringRefSize);
        result[i] = row;
      }
    }
    private void ReadParamPtrTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.ParamPtr];
      ParamPtrRow[] result = this.paramPtrTable = new ParamPtrRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.ParamPtr];
      for (int i = 0; i < n; i++){
        ParamPtrRow row;
        row.Param = c.ReadReference(this.tableRefSize[(int)TableIndices.Param]);
        result[i] = row;
      }
    }
    private void ReadPropertyTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.Property];
      PropertyRow[] result = this.propertyTable = new PropertyRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.Property];
      for (int i = 0; i < n; i++){
        PropertyRow row;
        row.Flags = c.ReadUInt16(); 
        row.Name = c.ReadReference(this.stringRefSize);
        row.Signature = c.ReadReference(this.blobRefSize);
        result[i] = row;
      }
    }
    private void ReadPropertyMapTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.PropertyMap];
      PropertyMapRow[] result = this.propertyMapTable = new PropertyMapRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.PropertyMap];
      for (int i = 0; i < n; i++){
        PropertyMapRow row;
        row.Parent = c.ReadReference(this.tableRefSize[(int)TableIndices.TypeDef]);
        row.PropertyList = c.ReadReference(this.tableRefSize[(int)TableIndices.Property]);
        result[i] = row;
      }
    }
    private void ReadPropertyPtrTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.PropertyPtr];
      PropertyPtrRow[] result = this.propertyPtrTable = new PropertyPtrRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.PropertyPtr];
      for (int i = 0; i < n; i++){
        PropertyPtrRow row;
        row.Property = c.ReadReference(this.tableRefSize[(int)TableIndices.Property]);
        result[i] = row;
      }
    }
    private void ReadStandAloneSigTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.StandAloneSig];
      StandAloneSigRow[] result = this.standAloneSigTable = new StandAloneSigRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.StandAloneSig];
      for (int i = 0; i < n; i++){
        StandAloneSigRow row;
        row.Signature = c.ReadReference(this.blobRefSize);
        result[i] = row;
      }
    }
    private void ReadTypeDefTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.TypeDef];
      TypeDefRow[] result = this.typeDefTable = new TypeDefRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.TypeDef];
      for (int i = 0; i < n; i++){
        TypeDefRow row;
        row.Flags = c.ReadInt32();
        row.Name = c.ReadReference(this.stringRefSize);
        row.Namespace = c.ReadReference(this.stringRefSize);
        row.Extends = c.ReadReference(this.typeDefOrRefOrSpecSize);
        row.FieldList = c.ReadReference(this.tableRefSize[(int)TableIndices.Field]);
        row.MethodList = c.ReadReference(this.tableRefSize[(int)TableIndices.Method]);
        row.Type = null;
        row.NameKey = 0;
        row.NamespaceId = null;
        row.NamespaceKey = 0;
        result[i] = row;
      }
      for (int i = 0; i < n; i++){
        result[i].NameKey = this.GetIdentifier(result[i].Name).UniqueIdKey;
        result[i].NamespaceId = this.GetIdentifier(result[i].Namespace);
        //^ assume result[i].NamespaceId != null;
        result[i].NamespaceKey = result[i].NamespaceId.UniqueIdKey;
      }
    }
    private void ReadTypeRefTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.TypeRef];
      TypeRefRow[] result = this.typeRefTable = new TypeRefRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.TypeRef];
      for (int i = 0; i < n; i++){
        TypeRefRow row;
        row.ResolutionScope = c.ReadReference(this.resolutionScopeRefSize);
        row.Name = c.ReadReference(this.stringRefSize);
        row.Namespace = c.ReadReference(this.stringRefSize);
        row.Type = null;
        result[i] = row;
      }
    }
    private void ReadTypeSpecTable()
      //^ requires this.tableSize != null;
      //^ requires this.tableOffset != null;
    {
      int n = this.tableSize[(int)TableIndices.TypeSpec];
      TypeSpecRow[] result = this.typeSpecTable = new TypeSpecRow[n];
      if (n == 0) return;
      MemoryCursor c = this.cursor;
      c.Position = this.tableOffset[(int)TableIndices.TypeSpec];
      for (int i = 0; i < n; i++){
        TypeSpecRow row;
        row.Signature = c.ReadReference(this.blobRefSize);
        row.Type = null;
        result[i] = row;
      }
    }
    internal int GetOffsetToEndOfSection(int virtualAddress){
      foreach (SectionHeader section in this.sectionHeaders)
        if (virtualAddress >= section.virtualAddress && virtualAddress < section.virtualAddress+section.sizeOfRawData)
          return (section.sizeOfRawData - (virtualAddress - section.virtualAddress));
      return -1;
    }
    internal bool NoOffsetFor(int virtualAddress){
      foreach (SectionHeader section in this.sectionHeaders)
        if (virtualAddress >= section.virtualAddress && virtualAddress < section.virtualAddress+section.sizeOfRawData)
          return false;
      return true;
    }
    private int RvaToOffset(int virtualAddress){
      foreach (SectionHeader section in this.sectionHeaders)
        if (virtualAddress >= section.virtualAddress && virtualAddress < section.virtualAddress+section.sizeOfRawData)
          return (virtualAddress - section.virtualAddress + section.pointerToRawData);
      throw new InvalidMetadataException(String.Format(CultureInfo.CurrentCulture,
        ExceptionStrings.UnknownVirtualAddress,virtualAddress));
    }
    private int RvaToOffset(int virtualAddress, out PESection targetSection){
      foreach (SectionHeader section in this.sectionHeaders)
        if (virtualAddress >= section.virtualAddress && virtualAddress < section.virtualAddress+section.sizeOfRawData){
          if (section.name == ".tls") targetSection = PESection.TLS;
          else if (section.name == ".sdata") targetSection = PESection.SData;
          else targetSection = PESection.Text;
          return (virtualAddress - section.virtualAddress + section.pointerToRawData);
        }
      throw new InvalidMetadataException(String.Format(
        CultureInfo.CurrentCulture, ExceptionStrings.UnknownVirtualAddress,+virtualAddress));
    }
    private static CLIHeader/*!*/ ReadCLIHeader(MemoryCursor/*!*/ c) {
      CLIHeader header = new CLIHeader();
      header.cb                      = c.Int32(0); c.SkipInt32(1);
      header.majorRuntimeVersion     = c.UInt16(0);
      header.minorRuntimeVersion     = c.UInt16(1); c.SkipUInt16(2);
      header.metaData                = ReadDirectoryEntry(c);
      header.flags                   = c.Int32(0);
      header.entryPointToken         = c.Int32(1); c.SkipInt32(2);
      header.resources               = ReadDirectoryEntry(c);
      header.strongNameSignature     = ReadDirectoryEntry(c);
      header.codeManagerTable        = ReadDirectoryEntry(c);
      header.vtableFixups            = ReadDirectoryEntry(c);
      header.exportAddressTableJumps = ReadDirectoryEntry(c);
      if (header.majorRuntimeVersion < 2)
        throw new InvalidMetadataException(ExceptionStrings.BadCLIHeader);
      return header;
    }
    private static DirectoryEntry ReadDirectoryEntry(MemoryCursor/*!*/ c) {
      DirectoryEntry entry = new DirectoryEntry();
      entry.virtualAddress = c.Int32(0);
      entry.size           = c.Int32(1); c.SkipInt32(2);
      return entry;
    }
    internal static void ReadDOSHeader(MemoryCursor/*!*/ c) {
      c.Position = 0;
      int magicNumber = c.UInt16(0);
      if (magicNumber != 0x5a4d) throw new InvalidMetadataException(ExceptionStrings.BadMagicNumber);
      c.Position = 0x3c;
      int ntHeaderOffset = c.Int32(0);
      c.Position = ntHeaderOffset;
    }
    private static MetadataHeader/*!*/ ReadMetadataHeader(MemoryCursor/*!*/ c) {
      MetadataHeader header = new MetadataHeader();
      header.signature      = c.ReadInt32();
      if (header.signature != 0x424a5342)
        throw new InvalidMetadataException(ExceptionStrings.BadMetadataHeaderSignature);
      header.majorVersion   = c.ReadUInt16();
      header.minorVersion   = c.ReadUInt16();
      header.reserved       = c.ReadInt32();      
      int len = c.ReadInt32();
      header.versionString = c.ReadASCII(len);
      while (len++ % 4 != 0) c.ReadByte();
      header.flags = c.ReadUInt16();
      int n = c.ReadUInt16();
      StreamHeader[] streamHeaders = header.streamHeaders = new StreamHeader[n];
      for (int i = 0; i < n; i++)
        streamHeaders[i] = ReadStreamHeader(c);
      return header;
    }
    internal static NTHeader/*!*/ ReadNTHeader(MemoryCursor/*!*/ c) {
      NTHeader header = new NTHeader();
      header.signature                   = c.ReadInt32();
      header.machine                     = c.ReadUInt16();
      header.numberOfSections            = c.ReadUInt16();
      header.timeDateStamp               = c.ReadInt32();
      header.pointerToSymbolTable        = c.ReadInt32();
      header.numberOfSymbols             = c.ReadInt32();
      header.sizeOfOptionalHeader        = c.ReadUInt16();
      header.characteristics             = c.ReadUInt16();
      header.magic                       = c.ReadUInt16();
      header.majorLinkerVersion          = c.ReadByte();
      header.minorLinkerVersion          = c.ReadByte();
      header.sizeOfCode                  = c.ReadInt32();
      header.sizeOfInitializedData       = c.ReadInt32();
      header.sizeOfUninitializedData     = c.ReadInt32();
      header.addressOfEntryPoint         = c.ReadInt32();
      header.baseOfCode                  = c.ReadInt32();
      if (header.magic == 0x10B){
        header.baseOfData                = c.ReadInt32();
        header.imageBase                 = c.ReadUInt32();
      }else{
        header.baseOfData                = 0;
        header.imageBase                 = c.ReadUInt64();
      }
      header.sectionAlignment            = c.ReadInt32();
      header.fileAlignment               = c.ReadInt32();
      header.majorOperatingSystemVersion = c.ReadUInt16();
      header.minorOperatingSystemVersion = c.ReadUInt16();
      header.majorImageVersion           = c.ReadUInt16();
      header.minorImageVersion           = c.ReadUInt16();
      header.majorSubsystemVersion       = c.ReadUInt16();
      header.minorSubsystemVersion       = c.ReadUInt16();
      header.win32VersionValue           = c.ReadInt32();
      header.sizeOfImage                 = c.ReadInt32();
      header.sizeOfHeaders               = c.ReadInt32();
      header.checkSum                    = c.ReadInt32();
      header.subsystem                   = c.ReadUInt16();
      header.dllCharacteristics          = c.ReadUInt16();
      if (header.magic == 0x10B){
        header.sizeOfStackReserve          = c.ReadInt32();
        header.sizeOfStackCommit           = c.ReadInt32();
        header.sizeOfHeapReserve           = c.ReadInt32();
        header.sizeOfHeapCommit            = c.ReadInt32();
      }else{
        header.sizeOfStackReserve          = c.ReadInt64();
        header.sizeOfStackCommit           = c.ReadInt64();
        header.sizeOfHeapReserve           = c.ReadInt64();
        header.sizeOfHeapCommit            = c.ReadInt64();
      }
      header.loaderFlags                 = c.ReadInt32();
      header.numberOfDataDirectories     = c.ReadInt32();

      // Verify that the header signature and magic number are valid
      if (header.signature != 0x00004550 /* "PE\0\0" */)
        throw new InvalidMetadataException(ExceptionStrings.BadCOFFHeaderSignature);
      if (header.magic != 0x010B && header.magic != 0x020B)
        throw new InvalidMetadataException(ExceptionStrings.BadPEHeaderMagicNumber);

      //Read the data directories
      header.exportTable = ReadDirectoryEntry(c);
      header.importTable = ReadDirectoryEntry(c);
      header.resourceTable = ReadDirectoryEntry(c);
      header.exceptionTable = ReadDirectoryEntry(c);
      header.certificateTable = ReadDirectoryEntry(c);
      header.baseRelocationTable = ReadDirectoryEntry(c);
      header.debugTable = ReadDirectoryEntry(c);
      header.copyrightTable = ReadDirectoryEntry(c);
      header.globalPointerTable = ReadDirectoryEntry(c);
      header.threadLocalStorageTable = ReadDirectoryEntry(c);
      header.loadConfigTable = ReadDirectoryEntry(c);
      header.boundImportTable = ReadDirectoryEntry(c);
      header.importAddressTable = ReadDirectoryEntry(c);
      header.delayImportTable = ReadDirectoryEntry(c);
      header.cliHeaderTable = ReadDirectoryEntry(c);
      header.reserved = ReadDirectoryEntry(c);

      return header;
    }
    internal static SectionHeader ReadSectionHeader(MemoryCursor/*!*/ c) {
      SectionHeader header = new SectionHeader();
      header.name                 = c.ReadASCII(8);
      header.virtualSize          = c.Int32(0);
      header.virtualAddress       = c.Int32(1);
      header.sizeOfRawData        = c.Int32(2);
      header.pointerToRawData     = c.Int32(3);
      header.pointerToRelocations = c.Int32(4);
      header.pointerToLinenumbers = c.Int32(5); c.SkipInt32(6);
      header.numberOfRelocations  = c.UInt16(0);
      header.numberOfLinenumbers  = c.UInt16(1); c.SkipInt16(2);
      header.characteristics      = c.Int32(0); c.SkipInt32(1);
      return header;
    }
    private static StreamHeader ReadStreamHeader(MemoryCursor/*!*/ c) {
      StreamHeader header = new StreamHeader();
      header.offset = c.ReadInt32();
      header.size = c.ReadInt32();
      header.name = c.ReadASCII();
      int n = header.name.Length+1;
      c.Position += (4-(n%4))%4;
      return header;
    }
    private static TablesHeader/*!*/ ReadTablesHeader(MemoryCursor/*!*/ c) {
      TablesHeader header = new TablesHeader();
      header.reserved    = c.ReadInt32(); // Must be zero
      header.majorVersion = c.ReadByte();  // Must be one
      header.minorVersion = c.ReadByte();  // Must be zero
      header.heapSizes    = c.ReadByte();  // Bits for heap sizes
      header.rowId        = c.ReadByte();  // log-base-2 of largest rowId
      header.maskValid    = c.ReadInt64(); // Present table counts
      header.maskSorted   = c.ReadInt64(); // Sorted tables
      int n = 0;
      ulong mask = (ulong)header.maskValid;
      while (mask != 0){
        if (mask % 2 == 1) n++;
        mask /= 2;
      }
      int[] countArray = header.countArray = new int[n];
      for (int i = 0; i < n; i++)
        countArray[i] = c.ReadInt32();
      return header;
    }
  }
#if !NoWriter
  internal class MetadataWriter{
    internal MemoryStream StringHeap;
    internal MemoryStream BlobHeap;
    internal MemoryStream UserstringHeap;
    internal MemoryStream ResourceDataHeap;
    internal MemoryStream SdataHeap;
    internal MemoryStream TlsHeap;
    internal Guid[] GuidHeap;
    internal MemoryStream MethodBodiesHeap;
    internal Win32ResourceList Win32Resources;
    internal AssemblyRow[] assemblyTable;
    internal AssemblyRefRow[] assemblyRefTable;
    internal ClassLayoutRow[] classLayoutTable;
    internal ConstantRow[] constantTable;
    internal CustomAttributeRow[] customAttributeTable;
    internal DeclSecurityRow[] declSecurityTable;
    internal EventMapRow[] eventMapTable;
    internal EventRow[] eventTable;
    internal ExportedTypeRow[] exportedTypeTable = null;
    internal FieldRow[] fieldTable;
    internal FieldLayoutRow[] fieldLayoutTable;
    internal FieldMarshalRow[] fieldMarshalTable = null;
    internal FieldRvaRow[] fieldRvaTable = null;
    internal FileRow[] fileTable;
    internal GenericParamRow[] genericParamTable;
    internal GenericParamConstraintRow[] genericParamConstraintTable;
    internal ImplMapRow[] implMapTable;
    internal InterfaceImplRow[] interfaceImplTable;
    internal ManifestResourceRow[] manifestResourceTable = null;
    internal MemberRefRow[] memberRefTable;
    internal MethodRow[] methodTable;
    internal MethodImplRow[] methodImplTable;
    internal MethodSemanticsRow[] methodSemanticsTable;
    internal MethodSpecRow[] methodSpecTable;
    internal ModuleRow[] moduleTable;
    internal ModuleRefRow[] moduleRefTable;
    internal NestedClassRow[] nestedClassTable;
    internal ParamRow[] paramTable;
    internal PropertyRow[] propertyTable;
    internal PropertyMapRow[] propertyMapTable;
    internal StandAloneSigRow[] standAloneSigTable;
    internal TypeDefRow[] typeDefTable;
    internal TypeRefRow[] typeRefTable;
    internal TypeSpecRow[] typeSpecTable;
    internal int entryPointToken;
    internal int fileAlignment;
    internal ulong baseAddress;
    internal long sizeOfStackReserve;
    internal ModuleKindFlags moduleKind;
    internal ushort dllCharacteristics;
    internal PEKindFlags peKind;
    internal bool TrackDebugData;
    internal bool UseGenerics = false;
    internal byte[] PublicKey;
    internal int SignatureKeyLength;

    private int blobRefSize;
    private int constantParentRefSize;
    private int customAttributeParentRefSize;
    private int customAttributeConstructorRefSize;
    private int declSecurityParentRefSize;
    private int fieldMarshalParentRefSize;
    private int guidRefSize;
    private int hasSemanticRefSize;
    private int implementationRefSize;
    private int methodDefOrRefSize;
    private int memberRefParentSize;
    private int memberForwardedRefSize;
    private int typeDefOrMethodDefSize;
    private int typeDefOrRefOrSpecSize;
    private int resolutionScopeRefSize;
    private int stringRefSize;
#if !ROTOR
    private ISymUnmanagedWriter symWriter;
#endif
    private int[] tableRefSize;
    private int[] tableSize;
    private long validMask;

#if !ROTOR
    internal MetadataWriter(ISymUnmanagedWriter symWriter){
      this.symWriter = symWriter;
    }
#else
    internal MetadataWriter(){
    }
#endif

    private void SerializeMetadata(BinaryWriter/*!*/ writer, int virtualAddressBase, Fixup/*!*/ sdataFixup, Fixup/*!*/ tlsFixup)
      //^ requires this.MethodBodiesHeap != null;
      //^ requires this.ResourceDataHeap != null;
      //^ requires this.StringHeap != null;
      //^ requires this.UserstringHeap != null;
      //^ requires this.BlobHeap != null;
      //^ requires this.GuidHeap != null;
      //^ requires TargetPlatform.TargetRuntimeVersion != null;
    {
      int tableOffset = 0;
      tableOffset += (int)this.MethodBodiesHeap.Length;
      this.MethodBodiesHeap.WriteTo(writer.BaseStream);
      while (tableOffset % 4 != 0) {writer.Write((byte)0); tableOffset++;}
      if (this.PublicKey != null && 0 < this.PublicKey.Length){
        this.cliHeader.strongNameSignature.virtualAddress = virtualAddressBase+72+tableOffset;
        int keysize = this.ComputeStrongNameSignatureSize();
        this.cliHeader.strongNameSignature.size = keysize;
        tableOffset += keysize;
        writer.BaseStream.Position += keysize;
      }
      if (this.ResourceDataHeap.Length > 0){
        this.cliHeader.resources.virtualAddress = virtualAddressBase+72+tableOffset;
        this.ResourceDataHeap.WriteTo(writer.BaseStream);
        int sizeOfResources = (int)this.ResourceDataHeap.Length;
        while (sizeOfResources % 4 != 0) {writer.Write((byte)0); sizeOfResources++;}
        this.cliHeader.resources.size = sizeOfResources;
        tableOffset += sizeOfResources;
      }
      this.cliHeader.metaData.virtualAddress = virtualAddressBase+72+tableOffset;
      int startPos = (int)writer.BaseStream.Position;
      writer.Write((int)0x424a5342); //Magic signature
      writer.Write((short)1); //Major version
      writer.Write((short)1); //Minor version
      writer.Write((int)0); //Reserved
      writer.Write((int)12); // version must be 12 chars
      char[] version = new char[12]; 
      char[] aversion = TargetPlatform.TargetRuntimeVersion.ToCharArray();
      Array.Copy(aversion, 0, version, 0, Math.Min(12, aversion.Length));
      writer.Write(version);
      writer.Write((short)0); //flags
      writer.Write((short)5); //number of streams
      int offsetFromStartOfMetadata = 108;
      writer.Write((int)offsetFromStartOfMetadata);
      int cbStringHeapPad = 0;
      offsetFromStartOfMetadata += (int)this.StringHeap.Length;
      while (offsetFromStartOfMetadata % 4 != 0) {
        offsetFromStartOfMetadata++;
        cbStringHeapPad++;
      }
      writer.Write((int)this.StringHeap.Length + cbStringHeapPad);
      writer.Write(new char[] { '#', 'S', 't', 'r', 'i', 'n', 'g', 's', '\0', '\0', '\0', '\0' });

      writer.Write((int)offsetFromStartOfMetadata);
      offsetFromStartOfMetadata += (int)this.UserstringHeap.Length;
      int cbUserStringHeapPad = 0;
      while (offsetFromStartOfMetadata % 4 != 0) {
        offsetFromStartOfMetadata++;
        cbUserStringHeapPad++;
      }

      writer.Write((int)this.UserstringHeap.Length + cbUserStringHeapPad);
      writer.Write(new char[] { '#', 'U', 'S', '\0' });

      writer.Write((int)offsetFromStartOfMetadata);
      writer.Write((int)this.BlobHeap.Length);
      writer.Write(new char[] { '#', 'B', 'l', 'o', 'b', '\0', '\0', '\0' });
      offsetFromStartOfMetadata += (int)this.BlobHeap.Length;
      while (offsetFromStartOfMetadata % 4 != 0) offsetFromStartOfMetadata++;
      writer.Write((int)offsetFromStartOfMetadata);
      writer.Write((int)this.GuidHeap.Length*16);
      writer.Write(new char[] { '#', 'G', 'U', 'I', 'D', '\0', '\0', '\0' });
      offsetFromStartOfMetadata += this.GuidHeap.Length*16;
      writer.Write((int)offsetFromStartOfMetadata);
      int tabsL = this.TablesLength();
      writer.Write((int)tabsL);
      writer.Write(new char[] { '#', '~', '\0', '\0' });
      this.StringHeap.WriteTo(writer.BaseStream);
      int p = (int)this.StringHeap.Length;// +cbStringHeapPad;
      while (p % 4 != 0) { writer.Write((byte)0); p++; }
      this.UserstringHeap.WriteTo(writer.BaseStream);
      p = (int)this.UserstringHeap.Length;// +cbUserStringHeapPad;
      while (p % 4 != 0) { writer.Write((byte)0); p++; }
      this.BlobHeap.WriteTo(writer.BaseStream);
      p = (int)this.BlobHeap.Length;
      while (p % 4 != 0){ writer.Write((byte)0); p++;}
      for (int i = 0, n = this.GuidHeap.Length; i < n; i++)
        writer.Write(this.GuidHeap[i].ToByteArray());
      this.SerializeTables(writer, virtualAddressBase+72, sdataFixup, tlsFixup);
      this.cliHeader.metaData.size = ((int)writer.BaseStream.Position) - startPos; 
    }
#if !ROTOR
    private unsafe void WriteReferenceToPDBFile(BinaryWriter/*!*/ writer, int virtualAddressBase, int fileBase)
      //^ requires this.symWriter != null;
    {
      int startPos = writer.BaseStream.Position;
      this.ntHeader.debugTable.virtualAddress = startPos-fileBase+virtualAddressBase;
      this.ntHeader.debugTable.size = 28;
      ImageDebugDirectory debugDir = new ImageDebugDirectory(true);
      uint pcData = 0;
      this.symWriter.GetDebugInfo(ref debugDir, 0, out pcData, IntPtr.Zero);
      byte[] data = new byte[pcData];
      fixed (byte* pb = data){
        this.symWriter.GetDebugInfo(ref debugDir, pcData, out pcData, (IntPtr)pb);
      }
      writer.Write((int)debugDir.Characteristics);
      writer.Write(this.ntHeader.timeDateStamp);
      writer.Write((ushort)debugDir.MajorVersion);
      writer.Write((ushort)debugDir.MinorVersion);
      writer.Write((int)debugDir.Type);
      writer.Write((int)debugDir.SizeOfData);
      writer.Write((int)startPos+28-fileBase+virtualAddressBase); //AddressOfRawData
      writer.Write((int)startPos+28); //PointerToRawData
      writer.Write((byte[])data);
    }
#endif
    private void SerializeTables(BinaryWriter/*!*/ writer, int mbRVAOffset, Fixup/*!*/ sdataFixup, Fixup/*!*/ tlsFixup)
      //^ requires this.StringHeap != null;
      //^ requires this.GuidHeap != null;
      //^ requires this.BlobHeap != null;
      //^ requires this.tableSize != null;
      //^ requires this.tableRefSize != null;
    {
      writer.Write((int)0); //Reserved
      if (this.UseGenerics) {
        writer.Write((byte)2); writer.Write((byte)0);
      } else {
        writer.Write((byte)1); writer.Write((byte)1);
      }
      byte heapSizes = 0;
      if (this.StringHeap.Length >= 0x10000) heapSizes |= 0x01;
      if (this.GuidHeap.Length >= 0x10000) heapSizes |= 0x02;
      if (this.BlobHeap.Length >= 0x10000) heapSizes |= 0x04;
      writer.Write(heapSizes);
      writer.Write((byte)0); //Reserved
      writer.Write(this.validMask); //Tables that are present
      if (this.UseGenerics)
        writer.Write((long)0x16003301fa00); //Tables that are sorted
      else
        writer.Write((long)0x02003301fa00); //Tables that are sorted
      int[] tableSize = this.tableSize;
      for (int i = 0, n = 0; i < (int)TableIndices.Count; i++)
        if ((n = tableSize[i]) > 0) writer.Write(n);
      if (this.moduleTable != null) this.SerializeModuleTable(writer);
      if (this.typeRefTable != null) this.SerializeTypeRefTable(writer);
      if (this.typeDefTable != null) this.SerializeTypeDefTable(writer);
      if (this.fieldTable != null) this.SerializeFieldTable(writer);
      if (this.methodTable != null) this.SerializeMethodTable(writer, mbRVAOffset);
      if (this.paramTable != null) this.SerializeParamTable(writer);
      if (this.interfaceImplTable != null) this.SerializeInterfaceImplTable(writer);
      if (this.memberRefTable != null) this.SerializeMemberRefTable(writer);
      if (this.constantTable != null) this.SerializeConstantTable(writer);
      if (this.customAttributeTable != null) this.SerializeCustomAttributeTable(writer);
      if (this.fieldMarshalTable != null) this.SerializeFieldMarshalTable(writer);
      if (this.declSecurityTable != null) this.SerializeDeclSecurityTable(writer);
      if (this.classLayoutTable != null) this.SerializeClassLayoutTable(writer);
      if (this.fieldLayoutTable != null) this.SerializeFieldLayoutTable(writer);
      if (this.standAloneSigTable != null) this.SerializeStandAloneSigTable(writer);
      if (this.eventMapTable != null) this.SerializeEventMapTable(writer);
      if (this.eventTable != null) this.SerializeEventTable(writer);
      if (this.propertyMapTable != null) this.SerializePropertyMapTable(writer);
      if (this.propertyTable != null) this.SerializePropertyTable(writer);
      if (this.methodSemanticsTable != null) this.SerializeMethodSemanticsTable(writer);
      if (this.methodImplTable != null) this.SerializeMethodImplTable(writer);
      if (this.moduleRefTable != null) this.SerializeModuleRefTable(writer);
      if (this.typeSpecTable != null) this.SerializeTypeSpecTable(writer);
      if (this.implMapTable != null) this.SerializeImplMapTable(writer);
      if (this.fieldRvaTable != null) this.SerializeFieldRvaTable(writer, mbRVAOffset, sdataFixup, tlsFixup);
      if (this.assemblyTable != null) this.SerializeAssemblyTable(writer);
      if (this.assemblyRefTable != null) this.SerializeAssemblyRefTable(writer);
      if (this.fileTable != null) this.SerializeFileTable(writer);
      if (this.exportedTypeTable != null) this.SerializeExportedTypeTable(writer);
      if (this.manifestResourceTable != null) this.SerializeManifestResourceTable(writer);
      if (this.nestedClassTable != null) this.SerializeNestedClassTable(writer);
      if (this.genericParamTable != null) this.SerializeGenericParamTable(writer);
      if (this.methodSpecTable != null) this.SerializeMethodSpecTable(writer);
      if (this.genericParamConstraintTable != null) this.SerializeGenericParamConstraintTable(writer);
    }
    private void SerializeAssemblyTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.assemblyTable != null;
    {
      int n = this.tableSize[(int)TableIndices.Assembly];
      for (int i = 0; i < n; i++){
        AssemblyRow row = this.assemblyTable[i];
        writer.Write((int)row.HashAlgId);
        writer.Write((short)row.MajorVersion);
        writer.Write((short)row.MinorVersion);
        writer.Write((short)row.BuildNumber);
        writer.Write((short)row.RevisionNumber);
        writer.Write((int)row.Flags);
        this.WriteReference(writer, row.PublicKey, this.blobRefSize);
        this.WriteReference(writer, row.Name, this.stringRefSize);
        this.WriteReference(writer, row.Culture, this.stringRefSize);
      }
    }
    private void SerializeAssemblyRefTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.assemblyRefTable != null;
    {
      int n = this.tableSize[(int)TableIndices.AssemblyRef];
      for (int i = 0; i < n; i++){
        AssemblyRefRow row = this.assemblyRefTable[i];
        writer.Write((short)row.MajorVersion);
        writer.Write((short)row.MinorVersion);
        writer.Write((short)row.BuildNumber);
        writer.Write((short)row.RevisionNumber);
        writer.Write((int)row.Flags);
        this.WriteReference(writer, row.PublicKeyOrToken, this.blobRefSize);
        this.WriteReference(writer, row.Name, this.stringRefSize);
        this.WriteReference(writer, row.Culture, this.stringRefSize);
        this.WriteReference(writer, row.HashValue, this.blobRefSize);
      }
    }
    private void SerializeClassLayoutTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.classLayoutTable != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.ClassLayout];
      for (int i = 0; i < n; i++){
        ClassLayoutRow row = this.classLayoutTable[i];
        writer.Write((short)row.PackingSize);
        writer.Write((int)row.ClassSize);
        this.WriteReference(writer, row.Parent, this.tableRefSize[(int)TableIndices.TypeDef]);
      }
    }
    private void SerializeConstantTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.constantTable != null;
    {
      int n = this.tableSize[(int)TableIndices.Constant];
      for (int i = 0; i < n; i++){
        ConstantRow row = this.constantTable[i];
        writer.Write((byte)row.Type);
        writer.Write((byte)0);
        this.WriteReference(writer, row.Parent, this.constantParentRefSize);
        this.WriteReference(writer, row.Value, this.blobRefSize);
      }
    }
    private void SerializeCustomAttributeTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.customAttributeTable != null;
    {
      int n = this.tableSize[(int)TableIndices.CustomAttribute];
      for (int i = 0; i < n; i++){
        CustomAttributeRow row = this.customAttributeTable[i];
        this.WriteReference(writer, row.Parent, this.customAttributeParentRefSize);
        this.WriteReference(writer, row.Constructor, this.customAttributeConstructorRefSize);
        this.WriteReference(writer, row.Value, this.blobRefSize);
      }
    }
    private void SerializeDeclSecurityTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.declSecurityTable != null;
    {
      int n = this.tableSize[(int)TableIndices.DeclSecurity];
      for (int i = 0; i < n; i++){
        DeclSecurityRow row = this.declSecurityTable[i];
        writer.Write((short)row.Action);
        this.WriteReference(writer, row.Parent, this.declSecurityParentRefSize);
        this.WriteReference(writer, row.PermissionSet, this.blobRefSize);
      }
    }
    private void SerializeEventMapTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.eventMapTable != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.EventMap];
      for (int i = 0; i < n; i++){
        EventMapRow row = this.eventMapTable[i];
        this.WriteReference(writer, row.Parent, this.tableRefSize[(int)TableIndices.TypeDef]);
        this.WriteReference(writer, row.EventList, this.tableRefSize[(int)TableIndices.Event]);
      }
    }
    private void SerializeEventTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.eventTable != null;
    {
      int n = this.tableSize[(int)TableIndices.Event];
      for (int i = 0; i < n; i++){
        EventRow row = this.eventTable[i];
        writer.Write((short)row.Flags);
        this.WriteReference(writer, row.Name, this.stringRefSize);
        this.WriteReference(writer, row.EventType, this.typeDefOrRefOrSpecSize);
      }
    }
    private void SerializeExportedTypeTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.exportedTypeTable != null;
    {
      int n = this.tableSize[(int)TableIndices.ExportedType];
      for (int i = 0; i < n; i++){
        ExportedTypeRow row = this.exportedTypeTable[i];
        writer.Write((int)row.Flags);
        writer.Write((int)row.TypeDefId);
        this.WriteReference(writer, row.TypeName, this.stringRefSize);
        this.WriteReference(writer, row.TypeNamespace, this.stringRefSize);
        this.WriteReference(writer, row.Implementation, this.implementationRefSize);
      }
    }
    private void SerializeFieldTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.fieldTable != null;
    {
      int n = this.tableSize[(int)TableIndices.Field];
      for (int i = 0; i < n; i++){
        FieldRow row = this.fieldTable[i];
        writer.Write((short)row.Flags);
        this.WriteReference(writer, row.Name, this.stringRefSize);
        this.WriteReference(writer, row.Signature, this.blobRefSize);
      }
    }
    private void SerializeFieldLayoutTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.fieldLayoutTable != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.FieldLayout];
      for (int i = 0; i < n; i++){
        FieldLayoutRow row = this.fieldLayoutTable[i];
        writer.Write((int)row.Offset);
        this.WriteReference(writer, row.Field, this.tableRefSize[(int)TableIndices.Field]);
      }
    }

    private void SerializeFieldMarshalTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.fieldMarshalTable != null;
    {
      int n = this.tableSize[(int)TableIndices.FieldMarshal];
      for (int i = 0; i < n; i++){
        FieldMarshalRow row = this.fieldMarshalTable[i];
        this.WriteReference(writer, row.Parent, this.fieldMarshalParentRefSize);
        this.WriteReference(writer, row.NativeType, this.blobRefSize);
      }
    }
    private void SerializeFieldRvaTable(BinaryWriter/*!*/ writer, int mbRVAOffset, Fixup/*!*/ sdataFixup, Fixup/*!*/ tlsFixup)
      //^ requires this.tableSize != null;
      //^ requires this.fieldRvaTable != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.FieldRva];
      for (int i = 0; i < n; i++){
        FieldRvaRow row = this.fieldRvaTable[i];
        switch (row.TargetSection){
          case PESection.SData:
          case PESection.TLS:
            Fixup fixup = new Fixup();
            fixup.fixupLocation = writer.BaseStream.Position;
            fixup.addressOfNextInstruction = row.RVA;
            if (row.TargetSection == PESection.SData){
              sdataFixup.nextFixUp = fixup;
              sdataFixup = fixup;
            }else{
              sdataFixup.nextFixUp = fixup;
              sdataFixup = fixup;
            }
            writer.Write((int)0);
            break;
          case PESection.Text:
            writer.Write((int)row.RVA+mbRVAOffset);
            break;
        }
        this.WriteReference(writer, row.Field, this.tableRefSize[(int)TableIndices.Field]);
      }
    }
    private void SerializeFileTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.fileTable != null;
    {
      int n = this.tableSize[(int)TableIndices.File];
      for (int i = 0; i < n; i++){
        FileRow row = this.fileTable[i];
        writer.Write((int)row.Flags);
        this.WriteReference(writer, row.Name, this.stringRefSize);
        this.WriteReference(writer, row.HashValue, this.blobRefSize);
      }
    }
    private void SerializeGenericParamTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.genericParamTable != null;
    {
      int n = this.tableSize[(int)TableIndices.GenericParam];
      bool reallyOldGenericsFileFormat = TargetPlatform.MajorVersion == 1 && TargetPlatform.MinorVersion == 0;
      bool oldGenericsFileFormat = TargetPlatform.MajorVersion == 1 && TargetPlatform.MinorVersion == 1;
      for (int i = 0; i < n; i++){
        GenericParamRow row = this.genericParamTable[i];
        writer.Write((short)row.Number);
        writer.Write((short)row.Flags);
        this.WriteReference(writer, row.Owner, this.typeDefOrMethodDefSize);
        this.WriteReference(writer, row.Name, this.stringRefSize);
        if (oldGenericsFileFormat) this.WriteReference(writer, 0, this.typeDefOrRefOrSpecSize);
        if (reallyOldGenericsFileFormat) writer.Write((short)0);
      }
    }
    private void SerializeGenericParamConstraintTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.genericParamConstraintTable != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.GenericParamConstraint];
      for (int i = 0; i < n; i++){
        GenericParamConstraintRow row = this.genericParamConstraintTable[i];
        this.WriteReference(writer, row.Param, this.tableRefSize[(int)TableIndices.GenericParam]);
        this.WriteReference(writer, row.Constraint, this.typeDefOrRefOrSpecSize);
      }
    }
    private void SerializeImplMapTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.implMapTable != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.ImplMap];
      for (int i = 0; i < n; i++){
        ImplMapRow row = this.implMapTable[i];
        writer.Write((short)row.MappingFlags);
        this.WriteReference(writer, row.MemberForwarded, this.memberForwardedRefSize);
        this.WriteReference(writer, row.ImportName, this.stringRefSize);
        this.WriteReference(writer, row.ImportScope, this.tableRefSize[(int)TableIndices.ModuleRef]);
      }
    }
    private void SerializeInterfaceImplTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.interfaceImplTable != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.InterfaceImpl];
      for (int i = 0; i < n; i++){
        InterfaceImplRow row = this.interfaceImplTable[i];
        this.WriteReference(writer, row.Class, this.tableRefSize[(int)TableIndices.TypeDef]);
        this.WriteReference(writer, row.Interface, this.typeDefOrRefOrSpecSize);
      }
    }
    private void SerializeManifestResourceTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.manifestResourceTable != null;
    {
      int n = this.tableSize[(int)TableIndices.ManifestResource];
      for (int i = 0; i < n; i++){
        ManifestResourceRow row = this.manifestResourceTable[i];
        writer.Write((int)row.Offset);
        writer.Write((int)row.Flags);
        this.WriteReference(writer, row.Name, this.stringRefSize);
        this.WriteReference(writer, row.Implementation, this.implementationRefSize);
      }
    }
    private void SerializeMemberRefTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.memberRefTable != null;
    {
      int n = this.tableSize[(int)TableIndices.MemberRef];
      for (int i = 0; i < n; i++){
        MemberRefRow row = this.memberRefTable[i];
        this.WriteReference(writer, row.Class, this.memberRefParentSize);
        this.WriteReference(writer, row.Name, this.stringRefSize);
        this.WriteReference(writer, row.Signature, this.blobRefSize);
      }
    }
    private void SerializeMethodTable(BinaryWriter/*!*/ writer, int mbRVAOffset)
      //^ requires this.tableSize != null;
      //^ requires this.methodTable != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.Method];
      int pn = this.paramTable == null ? 1 : this.paramTable.Length+1;
      for (int i = n-1; i >= 0; i--){
        MethodRow row = this.methodTable[i];
        if (row.ParamList != 0) pn = row.ParamList; else this.methodTable[i].ParamList = pn;
      }
      for (int i = 0; i < n; i++){
        MethodRow row = this.methodTable[i];
        if (row.RVA < 0)
          writer.Write((int)0);
        else
          writer.Write((int)row.RVA+mbRVAOffset);
        writer.Write((short)row.ImplFlags);
        writer.Write((short)row.Flags);
        this.WriteReference(writer, row.Name, this.stringRefSize);
        this.WriteReference(writer, row.Signature, this.blobRefSize);
        this.WriteReference(writer, row.ParamList, this.tableRefSize[(int)TableIndices.Param]);
      }
    }
    private void SerializeMethodImplTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.methodImplTable != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.MethodImpl];
      for (int i = 0; i < n; i++){
        MethodImplRow row = this.methodImplTable[i];
        this.WriteReference(writer, row.Class, this.tableRefSize[(int)TableIndices.TypeDef]);
        this.WriteReference(writer, row.MethodBody, this.methodDefOrRefSize);
        this.WriteReference(writer, row.MethodDeclaration, this.methodDefOrRefSize);
      }
    }
    private void SerializeMethodSemanticsTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.methodSemanticsTable != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.MethodSemantics];
      for (int i = 0; i < n; i++){
        MethodSemanticsRow row = this.methodSemanticsTable[i];
        writer.Write((short)row.Semantics);
        this.WriteReference(writer, row.Method, this.tableRefSize[(int)TableIndices.Method]);
        this.WriteReference(writer, row.Association, this.hasSemanticRefSize);
      }
    }
    private void SerializeMethodSpecTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.assemblyTable != null;
      //^ requires this.methodSpecTable != null;
    {
      int n = this.tableSize[(int)TableIndices.MethodSpec];
      for (int i = 0; i < n; i++){
        MethodSpecRow row = this.methodSpecTable[i];
        this.WriteReference(writer, row.Method, this.methodDefOrRefSize);
        this.WriteReference(writer, row.Instantiation, this.blobRefSize);
      }
    }
    private void SerializeModuleTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.moduleTable != null;
    {
      int n = this.tableSize[(int)TableIndices.Module];
      for (int i = 0; i < n; i++){
        ModuleRow row = this.moduleTable[i];
        writer.Write((short)row.Generation);
        this.WriteReference(writer, row.Name, this.stringRefSize);
        this.WriteReference(writer, row.Mvid, this.guidRefSize);
        this.WriteReference(writer, row.EncId, this.guidRefSize);
        this.WriteReference(writer, row.EncBaseId, this.guidRefSize);
      }
    }
    private void SerializeModuleRefTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.moduleRefTable != null;
    {
      int n = this.tableSize[(int)TableIndices.ModuleRef];
      for (int i = 0; i < n; i++){
        ModuleRefRow row = this.moduleRefTable[i];
        this.WriteReference(writer, row.Name, this.stringRefSize);
      }
    }
    private void SerializeNestedClassTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.nestedClassTable != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.NestedClass];
      for (int i = 0; i < n; i++){
        NestedClassRow row = this.nestedClassTable[i];
        this.WriteReference(writer, row.NestedClass, this.tableRefSize[(int)TableIndices.TypeDef]);
        this.WriteReference(writer, row.EnclosingClass, this.tableRefSize[(int)TableIndices.TypeDef]);
      }
    }
    private void SerializeParamTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.paramTable != null;
    {
      int n = this.tableSize[(int)TableIndices.Param];
      for (int i = 0; i < n; i++){
        ParamRow row = this.paramTable[i];
        writer.Write((short)row.Flags);
        writer.Write((short)row.Sequence);
        this.WriteReference(writer, row.Name, this.stringRefSize);
      }
    }
    private void SerializePropertyTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.propertyTable != null;
    {
      int n = this.tableSize[(int)TableIndices.Property];
      for (int i = 0; i < n; i++){
        PropertyRow row = this.propertyTable[i];
        writer.Write((short)row.Flags);
        this.WriteReference(writer, row.Name, this.stringRefSize);
        this.WriteReference(writer, row.Signature, this.blobRefSize);
      }
    }
    private void SerializePropertyMapTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.propertyMapTable != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.PropertyMap];
      for (int i = 0; i < n; i++){
        PropertyMapRow row = this.propertyMapTable[i];
        this.WriteReference(writer, row.Parent, this.tableRefSize[(int)TableIndices.TypeDef]);
        this.WriteReference(writer, row.PropertyList, this.tableRefSize[(int)TableIndices.Property]);
      }
    }
    private void SerializeStandAloneSigTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.assemblyTable != null;
      //^ requires this.standAloneSigTable != null;
    {
      int n = this.tableSize[(int)TableIndices.StandAloneSig];
      for (int i = 0; i < n; i++){
        StandAloneSigRow row = this.standAloneSigTable[i];
        this.WriteReference(writer, row.Signature, this.blobRefSize);
      }
    }
    private void SerializeTypeDefTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.typeDefTable != null;
      //^ requires this.tableRefSize != null;
    {
      int n = this.tableSize[(int)TableIndices.TypeDef];
      int fn = this.fieldTable == null ? 1 : this.fieldTable.Length+1;
      int mn = this.methodTable == null ? 1 : this.methodTable.Length+1;
      for (int i = n-1; i >= 0; i--){
        TypeDefRow row = this.typeDefTable[i];
        if (row.FieldList != 0) fn = row.FieldList; else this.typeDefTable[i].FieldList = fn;
        if (row.MethodList != 0) mn = row.MethodList; else this.typeDefTable[i].MethodList = mn;
      }
      for (int i = 0; i < n; i++){
        TypeDefRow row = this.typeDefTable[i];
        writer.Write((int)row.Flags);
        this.WriteReference(writer, row.Name, this.stringRefSize);
        this.WriteReference(writer, row.Namespace, this.stringRefSize);
        this.WriteReference(writer, row.Extends, this.typeDefOrRefOrSpecSize);
        this.WriteReference(writer, row.FieldList, this.tableRefSize[(int)TableIndices.Field]);
        this.WriteReference(writer, row.MethodList, this.tableRefSize[(int)TableIndices.Method]);
      }
    }
    private void SerializeTypeRefTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.typeRefTable != null;
    {
      int n = this.tableSize[(int)TableIndices.TypeRef];
      for (int i = 0; i < n; i++){
        TypeRefRow row = this.typeRefTable[i];
        this.WriteReference(writer, row.ResolutionScope, this.resolutionScopeRefSize);
        this.WriteReference(writer, row.Name, this.stringRefSize);
        this.WriteReference(writer, row.Namespace, this.stringRefSize);
      }
    }
    private void SerializeTypeSpecTable(BinaryWriter/*!*/ writer)
      //^ requires this.tableSize != null;
      //^ requires this.typeSpecTable != null;
    {
      int n = this.tableSize[(int)TableIndices.TypeSpec];
      for (int i = 0; i < n; i++){
        TypeSpecRow row = this.typeSpecTable[i];
        this.WriteReference(writer, row.Signature, this.blobRefSize);
      }
    }
    private int TablesLength()
      //^ requires this.BlobHeap != null;
      //^ requires this.GuidHeap != null;
      //^ requires this.StringHeap != null;
    {
      int[] tableSize = this.tableSize = new int[(int)TableIndices.Count];
      int[] tableRefSize = this.tableRefSize = new int[(int)TableIndices.Count];
      int tableCount = 0;
      long validMask = 0;
      for (int i = 0; i < (int)TableIndices.Count; i++){
        int j = 0;
        switch((TableIndices)i){
          case TableIndices.Module : if (this.moduleTable != null) j = this.moduleTable.Length; break;
          case TableIndices.TypeRef : if (this.typeRefTable != null) j = this.typeRefTable.Length; break;
          case TableIndices.TypeDef : if (this.typeDefTable != null) j = this.typeDefTable.Length; break;
          case TableIndices.Field : if (this.fieldTable != null) j = this.fieldTable.Length; break;
          case TableIndices.Method : if (this.methodTable != null) j = this.methodTable.Length; break;
          case TableIndices.Param : if (this.paramTable != null) j = this.paramTable.Length; break;
          case TableIndices.InterfaceImpl : if (this.interfaceImplTable != null) j = this.interfaceImplTable.Length; break;
          case TableIndices.MemberRef : if (this.memberRefTable != null) j = this.memberRefTable.Length; break;
          case TableIndices.Constant : if (this.constantTable != null) j = this.constantTable.Length; break;
          case TableIndices.CustomAttribute : if (this.customAttributeTable != null) j = this.customAttributeTable.Length; break;
          case TableIndices.FieldMarshal : if (this.fieldMarshalTable != null) j = this.fieldMarshalTable.Length; break;
          case TableIndices.DeclSecurity : if (this.declSecurityTable != null) j = this.declSecurityTable.Length; break;
          case TableIndices.ClassLayout : if (this.classLayoutTable != null) j = this.classLayoutTable.Length; break;
          case TableIndices.FieldLayout : if (this.fieldLayoutTable != null) j = this.fieldLayoutTable.Length; break;
          case TableIndices.StandAloneSig : if (this.standAloneSigTable != null) j = this.standAloneSigTable.Length; break;
          case TableIndices.EventMap : if (this.eventMapTable != null) j = this.eventMapTable.Length; break;
          case TableIndices.Event : if (this.eventTable != null) j = this.eventTable.Length; break;
          case TableIndices.PropertyMap : if (this.propertyMapTable != null) j = this.propertyMapTable.Length; break;
          case TableIndices.Property : if (this.propertyTable != null) j = this.propertyTable.Length; break;
          case TableIndices.MethodSemantics : if (this.methodSemanticsTable != null) j = this.methodSemanticsTable.Length; break;
          case TableIndices.MethodImpl : if (this.methodImplTable != null) j = this.methodImplTable.Length; break;
          case TableIndices.ModuleRef : if (this.moduleRefTable != null) j = this.moduleRefTable.Length; break;
          case TableIndices.TypeSpec : if (this.typeSpecTable != null) j = this.typeSpecTable.Length; break;
          case TableIndices.ImplMap : if (this.implMapTable != null) j = this.implMapTable.Length; break;
          case TableIndices.FieldRva : if (this.fieldRvaTable != null) j = this.fieldRvaTable.Length; break;
          case TableIndices.Assembly : if (this.assemblyTable != null) j = this.assemblyTable.Length; break;
          case TableIndices.AssemblyRef : if (this.assemblyRefTable != null) j = this.assemblyRefTable.Length; break;
          case TableIndices.File : if (this.fileTable != null) j = this.fileTable.Length; break;
          case TableIndices.ExportedType : if (this.exportedTypeTable != null) j = this.exportedTypeTable.Length; break;
          case TableIndices.ManifestResource : if (this.manifestResourceTable != null) j = this.manifestResourceTable.Length; break;
          case TableIndices.NestedClass : if (this.nestedClassTable != null) j = this.nestedClassTable.Length; break;
          case TableIndices.GenericParam: if (this.genericParamTable != null) j = this.genericParamTable.Length; break;
          case TableIndices.MethodSpec: if (this.methodSpecTable != null) j = this.methodSpecTable.Length; break;
          case TableIndices.GenericParamConstraint: if (this.genericParamConstraintTable != null) j = this.genericParamConstraintTable.Length; break;
        }
        tableSize[i] = j;
        if (j > 0){
          tableCount++;
          validMask |= 1L << i;
        }
      }
      this.validMask = validMask;

      for (int i = 0; i < (int)TableIndices.Count; i++)
        tableRefSize[i] = tableSize[i] < 0x10000 ? 2 : 4;
      int blobRefSize = this.blobRefSize = this.BlobHeap.Length < 0x10000 ? 2 : 4;
      int constantParentRefSize = this.constantParentRefSize = 
        tableSize[(int)TableIndices.Param] < 0x4000 && 
        tableSize[(int)TableIndices.Field] < 0x4000 && 
        tableSize[(int)TableIndices.Property] < 0x4000 ? 2 : 4;
      int customAttributeParentRefSize = this.customAttributeParentRefSize = 
        tableSize[(int)TableIndices.Method] < 0x0800 &&
        tableSize[(int)TableIndices.Field] < 0x0800 &&
        tableSize[(int)TableIndices.TypeRef] < 0x0800 &&
        tableSize[(int)TableIndices.TypeDef] < 0x0800 &&
        tableSize[(int)TableIndices.Param] < 0x0800 &&
        tableSize[(int)TableIndices.InterfaceImpl] < 0x0800 &&
        tableSize[(int)TableIndices.MemberRef] < 0x0800 &&
        tableSize[(int)TableIndices.Module] < 0x0800 &&
        tableSize[(int)TableIndices.DeclSecurity] < 0x0800 &&
        tableSize[(int)TableIndices.Property] < 0x0800 &&
        tableSize[(int)TableIndices.Event] < 0x0800 &&
        tableSize[(int)TableIndices.StandAloneSig] < 0x0800 &&
        tableSize[(int)TableIndices.ModuleRef] < 0x0800 &&
        tableSize[(int)TableIndices.TypeSpec] < 0x0800 &&
        tableSize[(int)TableIndices.Assembly] < 0x0800 &&
        tableSize[(int)TableIndices.File] < 0x0800 &&
        tableSize[(int)TableIndices.ExportedType] < 0x0800 &&
        tableSize[(int)TableIndices.ManifestResource] < 0x0800 &&
        tableSize[(int)TableIndices.GenericParam] < 0x0800 &&
        tableSize[(int)TableIndices.MethodSpec] < 0x0800 &&
        tableSize[(int)TableIndices.GenericParamConstraint] < 0x0800 ? 2 : 4;
      int customAttributeConstructorRefSize = this.customAttributeConstructorRefSize =
        tableSize[(int)TableIndices.Method] < 0x2000 &&
        tableSize[(int)TableIndices.MemberRef] < 0x2000 ? 2 : 4;
      int declSecurityParentRefSize = this.declSecurityParentRefSize = 
        tableSize[(int)TableIndices.TypeDef] < 0x4000 && 
        tableSize[(int)TableIndices.Method] < 0x4000 && 
        tableSize[(int)TableIndices.Assembly] < 0x4000 ? 2 : 4;
      int fieldMarshalParentRefSize = this.fieldMarshalParentRefSize = 
        tableSize[(int)TableIndices.Field] < 0x8000 && 
        tableSize[(int)TableIndices.Param] < 0x8000 ? 2 : 4;
      int guidRefSize = this.guidRefSize = this.GuidHeap.Length < 0x10000 ? 2 : 4;
      int hasSemanticRefSize = this.hasSemanticRefSize = 
        tableSize[(int)TableIndices.Event] < 0x8000 && 
        tableSize[(int)TableIndices.Property] < 0x8000 ? 2 : 4;
      int implementationRefSize = this.implementationRefSize = 
        tableSize[(int)TableIndices.File] < 0x4000 && 
        tableSize[(int)TableIndices.AssemblyRef] < 0x4000 && 
        tableSize[(int)TableIndices.ExportedType] < 0x4000 ? 2 : 4;
      int methodDefOrRefSize = this.methodDefOrRefSize = 
        tableSize[(int)TableIndices.Method] < 0x8000 && 
        tableSize[(int)TableIndices.MemberRef] < 0x8000 ? 2 : 4;
      int memberRefParentSize = this.memberRefParentSize =
        tableSize[(int)TableIndices.TypeDef] < 0x2000 &&
        tableSize[(int)TableIndices.TypeRef] < 0x2000 &&
        tableSize[(int)TableIndices.ModuleRef] < 0x2000 &&
        tableSize[(int)TableIndices.Method] < 0x2000 &&
        tableSize[(int)TableIndices.TypeSpec] < 0x2000 ? 2 : 4;
      int memberForwardedRefSize = this.memberForwardedRefSize = 
        tableSize[(int)TableIndices.Field] < 0x8000 && 
        tableSize[(int)TableIndices.Method] < 0x8000 ? 2 : 4;
      int typeDefOrMethodDefSize = this.typeDefOrMethodDefSize = 
        tableSize[(int)TableIndices.TypeDef] < 0x8000 && 
        tableSize[(int)TableIndices.Method] < 0x8000 ? 2 : 4;
      int typeDefOrRefOrSpecSize = this.typeDefOrRefOrSpecSize = 
        tableSize[(int)TableIndices.TypeDef] < 0x4000 && 
        tableSize[(int)TableIndices.TypeRef] < 0x4000 && 
        tableSize[(int)TableIndices.TypeSpec] < 0x4000 ? 2 : 4;
      int resolutionScopeRefSize = this.resolutionScopeRefSize =
        tableSize[(int)TableIndices.Module] < 0x4000 &&
        tableSize[(int)TableIndices.ModuleRef] < 0x4000 &&
        tableSize[(int)TableIndices.AssemblyRef] < 0x4000 &&
        tableSize[(int)TableIndices.TypeRef] < 0x4000 ? 2 : 4;
      int stringRefSize = this.stringRefSize = this.StringHeap.Length < 0x10000 ? 2 : 4;

      int length = 0;
      for (int i = 0; i < (int)TableIndices.Count; i++){
        int m = tableSize[i];
        if (m == 0) continue;
        switch((TableIndices)i){
          case TableIndices.Module : length += m * (2 + stringRefSize + 3*guidRefSize); break;
          case TableIndices.TypeRef : length += m * (resolutionScopeRefSize + 2*stringRefSize); break;
          case TableIndices.TypeDef : length += m * (4 + 2*stringRefSize + typeDefOrRefOrSpecSize + tableRefSize[(int)TableIndices.Field] + tableRefSize[(int)TableIndices.Method]); break;
          case TableIndices.Field : length += m * (2 + stringRefSize + blobRefSize); break;
          case TableIndices.Method : length += m * (8 + stringRefSize + blobRefSize + tableRefSize[(int)TableIndices.Param]); break;
          case TableIndices.Param : length += m * (4 + stringRefSize); break;
          case TableIndices.InterfaceImpl : length += m * (tableRefSize[(int)TableIndices.TypeDef]+typeDefOrRefOrSpecSize); break;
          case TableIndices.MemberRef : length += m * (memberRefParentSize + stringRefSize + blobRefSize); break;
          case TableIndices.Constant : length += m * (2 + constantParentRefSize + blobRefSize); break;
          case TableIndices.CustomAttribute : length += m * (customAttributeParentRefSize + customAttributeConstructorRefSize + blobRefSize); break;
          case TableIndices.FieldMarshal : length += m * (fieldMarshalParentRefSize + blobRefSize); break;
          case TableIndices.DeclSecurity : length += m * (2 + declSecurityParentRefSize + blobRefSize); break;
          case TableIndices.ClassLayout : length += m * (6 + tableRefSize[(int)TableIndices.TypeDef]); break;
          case TableIndices.FieldLayout : length += m * (4 + tableRefSize[(int)TableIndices.Field]); break;
          case TableIndices.StandAloneSig : length += m * (blobRefSize); break;
          case TableIndices.EventMap : length += m * (tableRefSize[(int)TableIndices.TypeDef] + tableRefSize[(int)TableIndices.Event]); break;
          case TableIndices.Event : length += m * (2 + stringRefSize + typeDefOrRefOrSpecSize); break;
          case TableIndices.PropertyMap : length += m * (tableRefSize[(int)TableIndices.TypeDef] + tableRefSize[(int)TableIndices.Property]); break;
          case TableIndices.Property : length += m * (2 + stringRefSize + blobRefSize); break;
          case TableIndices.MethodSemantics : length += m * (2 + tableRefSize[(int)TableIndices.Method] + hasSemanticRefSize); break;
          case TableIndices.MethodImpl : length += m * (tableRefSize[(int)TableIndices.TypeDef] + 2*methodDefOrRefSize); break;
          case TableIndices.ModuleRef : length += m * (stringRefSize); break;
          case TableIndices.TypeSpec : length += m * (blobRefSize); break;
          case TableIndices.ImplMap : length += m * (2 + memberForwardedRefSize + stringRefSize + tableRefSize[(int)TableIndices.ModuleRef]); break;
          case TableIndices.FieldRva : length += m * (4 + tableRefSize[(int)TableIndices.Field]); break;
          case TableIndices.EncLog: throw new InvalidMetadataException(ExceptionStrings.ENCLogTableEncountered);
          case TableIndices.EncMap: throw new InvalidMetadataException(ExceptionStrings.ENCMapTableEncountered);
          case TableIndices.Assembly : length += m * (16 + blobRefSize + 2*stringRefSize); break;
          case TableIndices.AssemblyRef : length += m * (12 + 2*blobRefSize + 2*stringRefSize); break;
          case TableIndices.File : length += m * (4 + stringRefSize + blobRefSize); break;
          case TableIndices.ExportedType : length += m * (8 + 2*stringRefSize + implementationRefSize); break;
          case TableIndices.ManifestResource : length += m * (8 + stringRefSize + implementationRefSize); break;
          case TableIndices.NestedClass : length += m * (2*tableRefSize[(int)TableIndices.TypeDef]); break;
          case TableIndices.GenericParam: 
            if (TargetPlatform.MajorVersion == 1 && TargetPlatform.MinorVersion == 0)
              length += m * (6 + typeDefOrMethodDefSize + stringRefSize + typeDefOrRefOrSpecSize);
            else if (TargetPlatform.MajorVersion == 1 && TargetPlatform.MinorVersion == 1)
              length += m * (4 + typeDefOrMethodDefSize + stringRefSize + typeDefOrRefOrSpecSize);
            else
              length += m * (4 + typeDefOrMethodDefSize + stringRefSize);
            break;
          case TableIndices.MethodSpec: length += m * (methodDefOrRefSize + blobRefSize); break;
          case TableIndices.GenericParamConstraint: length += m * (tableRefSize[(int)TableIndices.GenericParam] + typeDefOrRefOrSpecSize); break;
        }
      }
      length += 24+(tableCount*4);
      return length;
    }

    private NTHeader/*!*/ ntHeader = new NTHeader();
    private CLIHeader/*!*/ cliHeader = new CLIHeader();
    private SectionHeader[] sectionHeaders;

    internal void WritePE(BinaryWriter/*!*/ writer)
      //^ requires this.SdataHeap != null;
      //^ requires this.TlsHeap != null;
    {
      this.cliHeader.entryPointToken = this.entryPointToken;
      switch (this.moduleKind){
        case ModuleKindFlags.ConsoleApplication: 
          this.ntHeader.subsystem = 3;
          break;
        case ModuleKindFlags.DynamicallyLinkedLibrary:
          this.ntHeader.characteristics |= 0x2000;
          this.ntHeader.subsystem = 3;
          break;
        case ModuleKindFlags.WindowsApplication:
          this.ntHeader.subsystem = 2;
          break;
      }
      this.ntHeader.dllCharacteristics = (ushort)(this.dllCharacteristics|0x400);
      int numSectionHeaders = 2;
      if (this.SdataHeap.Length > 0) numSectionHeaders++;
      if (this.TlsHeap.Length > 0) numSectionHeaders++;
      if (this.Win32Resources != null && this.Win32Resources.Count > 0) numSectionHeaders++;
      this.sectionHeaders = new SectionHeader[numSectionHeaders];
      this.ntHeader.numberOfSections = (ushort)numSectionHeaders;
      this.ntHeader.timeDateStamp = (int)((DateTime.Now.ToUniversalTime() - NineteenSeventy).TotalSeconds);
    
      //Write out .text section for meta data tables, method bodies, address tables and entry point stub
      Fixup sdataFixup = new Fixup();
      Fixup tlsFixup = new Fixup();
      SectionHeader textSection = new SectionHeader();
      textSection.name = ".text";
      textSection.virtualAddress = 8192;
      int sizeOfPeHeaders = 376 + 40*numSectionHeaders;
      if ((this.peKind & PEKindFlags.Requires64bits) != 0) sizeOfPeHeaders += 16;
      textSection.pointerToRawData = ((int)Math.Ceiling(sizeOfPeHeaders / (double)this.fileAlignment)) * this.fileAlignment;
      textSection.characteristics = 0x60000020;      
      writer.BaseStream.Position = textSection.pointerToRawData+72; //Leave 72 bytes for CLI header
      this.SerializeMetadata(writer, textSection.virtualAddress, sdataFixup, tlsFixup);
      int RVAofEntryPointJumpTarget = this.WriteImportTableAndEntryPointStub(writer, ref textSection);
#if !ROTOR
      if (this.symWriter != null) this.WriteReferenceToPDBFile(writer, textSection.virtualAddress, textSection.pointerToRawData);
#endif
      int len = textSection.virtualSize = ((int)writer.BaseStream.Position) - textSection.pointerToRawData;
      textSection.sizeOfRawData = ((int)Math.Ceiling(len / (double)this.fileAlignment))*this.fileAlignment;
      this.sectionHeaders[0] = textSection;
      writer.BaseStream.Position = textSection.pointerToRawData;
      this.ntHeader.cliHeaderTable.virtualAddress = textSection.virtualAddress;
      this.ntHeader.cliHeaderTable.size = 72;
      WriteCLIHeader(writer); //Write CLI header last so that forward pointers can be filled in first

      int sectionHeaderIndex = 1;
      SectionHeader previousSection = textSection;
      int n = this.ntHeader.sectionAlignment;
      int m = this.fileAlignment;

      if (this.SdataHeap.Length > 0){
        SectionHeader sdataSection = new SectionHeader();
        sdataSection.name = ".sdata";
        int vaddr = sdataSection.virtualAddress = previousSection.virtualAddress + n * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)n);
        sdataSection.virtualSize = this.SdataHeap.Length;
        sdataSection.pointerToRawData = previousSection.pointerToRawData + m * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)m);
        sdataSection.characteristics = unchecked((int)0xC0000040);
        writer.BaseStream.Position = sdataSection.pointerToRawData;
        this.SdataHeap.WriteTo(writer.BaseStream);
        len = sdataSection.virtualSize = ((int)writer.BaseStream.Position) - sdataSection.pointerToRawData;
        writer.BaseStream.Position += m - (len % this.fileAlignment) - 1;
        writer.Write((byte)0);
        sdataSection.sizeOfRawData = ((int)Math.Ceiling(len / (double)this.fileAlignment))*this.fileAlignment;
        sdataFixup = sdataFixup.nextFixUp; //Skip over dummy header
        while (sdataFixup != null){
          writer.BaseStream.Position = sdataFixup.fixupLocation;
          writer.Write((int)(vaddr + sdataFixup.addressOfNextInstruction));
          sdataFixup = sdataFixup.nextFixUp;
        }
        this.sectionHeaders[sectionHeaderIndex++] = sdataSection;
        previousSection = sdataSection;
      }

      if (this.TlsHeap.Length > 0){
        SectionHeader tlsSection = new SectionHeader();
        tlsSection.name = ".tls";
        int vaddr = tlsSection.virtualAddress = previousSection.virtualAddress + n * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)n);
        tlsSection.virtualSize = this.SdataHeap.Length;
        tlsSection.pointerToRawData = previousSection.pointerToRawData + m * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)m);
        tlsSection.characteristics = unchecked((int)0xC0000040);
        writer.BaseStream.Position = tlsSection.pointerToRawData;
        this.TlsHeap.WriteTo(writer.BaseStream);
        len = tlsSection.virtualSize = ((int)writer.BaseStream.Position) - tlsSection.pointerToRawData;
        writer.BaseStream.Position += m - (len % this.fileAlignment) - 1;
        writer.Write((byte)0);
        tlsSection.sizeOfRawData = ((int)Math.Ceiling(len / (double)this.fileAlignment))*this.fileAlignment;
        tlsFixup = tlsFixup.nextFixUp; //Skip over dummy header
        while (tlsFixup != null){
          writer.BaseStream.Position = tlsFixup.fixupLocation;
          writer.Write((int)(vaddr + tlsFixup.addressOfNextInstruction));
          tlsFixup = tlsFixup.nextFixUp;
        }
        this.sectionHeaders[sectionHeaderIndex++] = tlsSection;
        previousSection = tlsSection;
      }

      if (this.Win32Resources != null && this.Win32Resources.Count > 0){
        SectionHeader rsrcSection = new SectionHeader();
        rsrcSection.name = ".rsrc";
        rsrcSection.virtualAddress = previousSection.virtualAddress + n * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)n);
        rsrcSection.pointerToRawData = previousSection.pointerToRawData + m * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)m);
        rsrcSection.characteristics = 0x40000040;
        writer.BaseStream.Position = rsrcSection.pointerToRawData;
        this.WriteWin32Resources(writer, rsrcSection.virtualAddress);
        len = rsrcSection.virtualSize = ((int)writer.BaseStream.Position) - rsrcSection.pointerToRawData;
        writer.BaseStream.Position += m - (len % this.fileAlignment) - 1;
        writer.Write((byte)0);
        rsrcSection.sizeOfRawData = ((int)Math.Ceiling(len / (double)this.fileAlignment))*this.fileAlignment;
        this.sectionHeaders[sectionHeaderIndex++] = rsrcSection;
        this.ntHeader.resourceTable.virtualAddress = rsrcSection.virtualAddress;
        this.ntHeader.resourceTable.size = rsrcSection.virtualSize;
        this.ntHeader.sizeOfInitializedData += rsrcSection.sizeOfRawData;
        previousSection = rsrcSection;
      }

      //Write out .reloc section for entry point stub relocation table
      bool IA64 = (this.peKind & PEKindFlags.Requires64bits) != 0 && (this.peKind & PEKindFlags.AMD) == 0;
      SectionHeader relocSection = new SectionHeader();
      relocSection.name = ".reloc";
      relocSection.virtualAddress = previousSection.virtualAddress + n * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)n);
      relocSection.virtualSize = IA64 ? 14 : 12;
      relocSection.pointerToRawData = previousSection.pointerToRawData + m * (int)Math.Ceiling(previousSection.sizeOfRawData / (double)m);
      relocSection.sizeOfRawData = m;
      relocSection.characteristics = 0x42000040;
      writer.BaseStream.Position = relocSection.pointerToRawData;
      writer.Write((int)((RVAofEntryPointJumpTarget / 4096) * 4096)); //Page RVA
      writer.Write((int)(IA64 ? 14 :12));
      int offsetWithinPage = RVAofEntryPointJumpTarget % 4096;
      int relocType = ((this.peKind & PEKindFlags.Requires64bits) != 0) ? 10 : 3;
      short s = (short)(relocType << 12 | offsetWithinPage);
      writer.Write(s);
      if (IA64) writer.Write((short)(relocType << 12));
      writer.Write((short)0); //next chunk's RVA
      writer.BaseStream.Position += m - 13;
      writer.Write((byte)0);
      this.sectionHeaders[sectionHeaderIndex] = relocSection;
      this.ntHeader.baseRelocationTable.virtualAddress = relocSection.virtualAddress;
      this.ntHeader.baseRelocationTable.size = relocSection.virtualSize;
      this.ntHeader.sizeOfInitializedData += relocSection.sizeOfRawData;

      //Write PE headers. Do this last because forward pointers are filled in by preceding code
      writer.BaseStream.Position = 0;
      writer.Write(dosHeader);
      WriteNTHeader(writer);
      WriteSectionHeaders(writer);
    }
    private class Directory{
      readonly internal string Name;
      readonly internal int ID;
      internal int NumberOfNamedEntries;
      internal int NumberOfIdEntries;
      readonly internal ArrayList/*!*/ Entries;
      internal Directory(string Name, int ID) {
        this.Name = Name;
        this.ID = ID;
        this.Entries = new ArrayList();
        //^ base();
      }
    }
    private void WriteWin32Resources(BinaryWriter/*!*/ writer, int virtualAddressBase) 
      //^ requires this.Win32Resources != null;
    {
      Win32ResourceList rsrcs = this.Win32Resources;
      BinaryWriter dataHeap = new BinaryWriter(new MemoryStream(), System.Text.Encoding.Unicode);
      //Construct a tree of array lists to represent the directory and make it easier to compute offsets
      Directory TypeDirectory = new Directory("", 0);
      Directory NameDirectory = null;
      Directory LanguageDirectory = null;
      int lastTypeID = int.MinValue;
      string lastTypeName = null;
      int lastID = int.MinValue;
      string lastName = null;
      int sizeOfDirectoryTree = 16;
      for (int i = 0, n = rsrcs.Count; i < n; i++){
        Win32Resource r = rsrcs[i];
        bool typeDifferent = (r.TypeId < 0 && r.TypeName != lastTypeName) || r.TypeId > lastTypeID;
        if (typeDifferent){
          lastTypeID = r.TypeId;
          lastTypeName = r.TypeName;
          if (lastTypeID < 0) TypeDirectory.NumberOfNamedEntries++; else TypeDirectory.NumberOfIdEntries++;
          sizeOfDirectoryTree += 24;
          TypeDirectory.Entries.Add(NameDirectory = new Directory(lastTypeName, lastTypeID));
        }
        //^ assume NameDirectory != null;
        if (typeDifferent || (r.Id < 0 && r.Name != lastName) || r.Id > lastID){
          lastID = r.Id;
          lastName = r.Name;
          if (lastID < 0) NameDirectory.NumberOfNamedEntries++; else NameDirectory.NumberOfIdEntries++;
          sizeOfDirectoryTree += 24;
          NameDirectory.Entries.Add(LanguageDirectory = new Directory(lastName, lastID));
        }
        //^ assume LanguageDirectory != null;
        LanguageDirectory.NumberOfIdEntries++;
        sizeOfDirectoryTree += 8;
        LanguageDirectory.Entries.Add(r);
        continue;
      }
      this.WriteDirectory(TypeDirectory, writer, 0, 0, sizeOfDirectoryTree, virtualAddressBase, dataHeap);
      dataHeap.BaseStream.WriteTo(writer.BaseStream);
    }
    private void WriteDirectory(Directory/*!*/ directory, BinaryWriter/*!*/ writer, int offset, int level, int sizeOfDirectoryTree,
      int virtualAddressBase, BinaryWriter/*!*/ dataHeap) {
      writer.Write((int)0); //Characteristics
      writer.Write((int)0); //Timestamp
      writer.Write((int)0); //Version
      writer.Write((short)directory.NumberOfNamedEntries);
      writer.Write((short)directory.NumberOfIdEntries);
      int n = directory.Entries.Count;
      int k = offset + 16 + n * 8;
      for (int i = 0; i < n; i++){
        int id = int.MinValue;
        string name = null;
        int nOff = dataHeap.BaseStream.Position+sizeOfDirectoryTree;
        int dOff = k;
        Directory subDir = directory.Entries[i] as Directory;
        if (subDir != null){
          id = subDir.ID;
          name = subDir.Name;
          if (level == 0)
            k += this.SizeOfDirectory(subDir);
          else
            k += 16 + 8 * subDir.Entries.Count;
        }else{
          Win32Resource r = (Win32Resource)directory.Entries[i];
          id = level == 0 ? r.TypeId : level == 1 ? r.Id : r.LanguageId;
          name = level == 0 ? r.TypeName : level == 1 ? r.Name : null;
          dataHeap.Write((int)(virtualAddressBase+sizeOfDirectoryTree+16+dataHeap.BaseStream.Position));
          dataHeap.Write((int)r.Data.Length);
          dataHeap.Write((int)r.CodePage);
          dataHeap.Write((int)0);
          dataHeap.Write(r.Data);
        }
        if (id >= 0)
          writer.Write(id);
        else{
          if (name == null) name = "";
          writer.Write(((uint)nOff)|0x80000000);
          dataHeap.Write((ushort)name.Length); 
          dataHeap.Write(name.ToCharArray());  //REVIEW: what happens if the name contains chars that do not fit into a single utf8 code point?
        }
        if (subDir != null)
          writer.Write(((uint)dOff)|0x80000000);
        else
          writer.Write(nOff);
      }
      k = offset + 16 + n * 8;
      for (int i = 0; i < n; i++){
        Directory subDir = directory.Entries[i] as Directory;
        if (subDir != null){
          this.WriteDirectory(subDir, writer, k, level+1, sizeOfDirectoryTree, virtualAddressBase, dataHeap);
          if (level == 0)
            k += this.SizeOfDirectory(subDir);
          else
            k += 16 + 8 * subDir.Entries.Count;
        }
      }      
    }
    private int SizeOfDirectory(Directory/*!*/ directory) {
      int n = directory.Entries.Count;
      int size = 16 + 8 * n;
      for (int i = 0; i < n; i++){
        Directory subDir = directory.Entries[i] as Directory;
        if (subDir != null)
          size += 16 + 8 * subDir.Entries.Count;
      }
      return size;
    }
    private static readonly byte[] dosHeader = new byte[]{
       0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00,
       0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
       0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
       0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd,
       0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
       0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,
       0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
       0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e,
       0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
       0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,
       0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };

    static readonly DateTime NineteenSeventy = new DateTime(1970, 1, 1);
    private void WriteNTHeader(BinaryWriter/*!*/ writer)
      //^ requires this.sectionHeaders != null;
    {
      NTHeader ntHeader = this.ntHeader;
      writer.Write(ntHeader.signature);
      if ((this.peKind & PEKindFlags.Requires64bits) == 0){
        if ((this.peKind & PEKindFlags.Requires32bits) != 0)
          ntHeader.characteristics |= 0x0100; //32 bit machine (The standard says to always set this, the linker team says otherwise)
        ntHeader.magic = 0x10B; //PE32
        ntHeader.machine = 0x014c; //I386
      }else{
        ntHeader.characteristics |= 0x0020; //Can handle >2gb addresses
        ntHeader.magic = 0x20B; //PE32+
        if ((this.peKind & PEKindFlags.AMD) != 0)
          ntHeader.machine = 0x8664; //AMD64
        else
          ntHeader.machine = 0x0200; //IA64
        ntHeader.sizeOfOptionalHeader += 16;
      }
      writer.Write(ntHeader.machine);
      writer.Write(ntHeader.numberOfSections);
      writer.Write(ntHeader.timeDateStamp);
      writer.Write(ntHeader.pointerToSymbolTable);
      writer.Write(ntHeader.numberOfSymbols);
      writer.Write(ntHeader.sizeOfOptionalHeader);
      writer.Write(ntHeader.characteristics);
      writer.Write(ntHeader.magic);
      writer.Write((byte)TargetPlatform.LinkerMajorVersion);
      writer.Write((byte)TargetPlatform.LinkerMinorVersion);
      writer.Write(this.sectionHeaders[0].sizeOfRawData); //sizeOfCode
      writer.Write(ntHeader.sizeOfInitializedData);
      writer.Write(ntHeader.sizeOfUninitializedData);
      writer.Write(ntHeader.addressOfEntryPoint);
      writer.Write(this.sectionHeaders[0].virtualAddress);  //baseOfCode
      if (ntHeader.magic == 0x10B){
        if (this.sectionHeaders.Length > 1)
          writer.Write(this.sectionHeaders[1].virtualAddress);  //baseOfData
        else
          writer.Write((int)0);
        writer.Write((int)ntHeader.imageBase); // don't use the imageBase read in from the input assembly: it creates bad modules.
      }else{
        writer.Write(this.baseAddress); // imageBase
      }
      writer.Write(ntHeader.sectionAlignment);
      writer.Write(this.fileAlignment);
      writer.Write(ntHeader.majorOperatingSystemVersion);
      writer.Write(ntHeader.minorOperatingSystemVersion);
      writer.Write(ntHeader.majorImageVersion);
      writer.Write(ntHeader.minorImageVersion);
      writer.Write(ntHeader.majorSubsystemVersion);
      writer.Write(ntHeader.minorSubsystemVersion);
      writer.Write(ntHeader.win32VersionValue);
      int sectionPages = (int)(Math.Ceiling(this.sectionHeaders[this.sectionHeaders.Length-1].virtualSize / 
                                           (double)ntHeader.sectionAlignment) * ntHeader.sectionAlignment);
      writer.Write(this.sectionHeaders[this.sectionHeaders.Length-1].virtualAddress + sectionPages); //sizeOfImage
      writer.Write(this.sectionHeaders[0].pointerToRawData); //sizeOfHeaders
      writer.Write(ntHeader.checkSum);
      writer.Write(ntHeader.subsystem);
      writer.Write(ntHeader.dllCharacteristics);
      if (ntHeader.magic == 0x10B){
        writer.Write((int)this.sizeOfStackReserve);
        writer.Write((int)ntHeader.sizeOfStackCommit);
        writer.Write((int)ntHeader.sizeOfHeapReserve);
        writer.Write((int)ntHeader.sizeOfHeapCommit);
      }else{
        writer.Write(this.sizeOfStackReserve);
        writer.Write(ntHeader.sizeOfStackCommit);
        writer.Write(ntHeader.sizeOfHeapReserve);
        writer.Write(ntHeader.sizeOfHeapCommit);
      }
      writer.Write(ntHeader.loaderFlags);
      writer.Write(ntHeader.numberOfDataDirectories);
      writer.Write(ntHeader.exportTable.virtualAddress);
      writer.Write(ntHeader.exportTable.size);
      writer.Write(ntHeader.importTable.virtualAddress);
      writer.Write(ntHeader.importTable.size);
      writer.Write(ntHeader.resourceTable.virtualAddress);
      writer.Write(ntHeader.resourceTable.size);
      writer.Write(ntHeader.exceptionTable.virtualAddress);
      writer.Write(ntHeader.exceptionTable.size);
      writer.Write(ntHeader.certificateTable.virtualAddress);
      writer.Write(ntHeader.certificateTable.size);
      writer.Write(ntHeader.baseRelocationTable.virtualAddress);
      writer.Write(ntHeader.baseRelocationTable.size);
      writer.Write(ntHeader.debugTable.virtualAddress);
      writer.Write(ntHeader.debugTable.size);
      writer.Write(ntHeader.copyrightTable.virtualAddress);
      writer.Write(ntHeader.copyrightTable.size);
      writer.Write(ntHeader.globalPointerTable.virtualAddress);
      writer.Write(ntHeader.globalPointerTable.size);
      writer.Write(ntHeader.threadLocalStorageTable.virtualAddress);
      writer.Write(ntHeader.threadLocalStorageTable.size);
      writer.Write(ntHeader.loadConfigTable.virtualAddress);
      writer.Write(ntHeader.loadConfigTable.size);
      writer.Write(ntHeader.boundImportTable.virtualAddress);
      writer.Write(ntHeader.boundImportTable.size);
      writer.Write(ntHeader.importAddressTable.virtualAddress);
      writer.Write(ntHeader.importAddressTable.size);
      writer.Write(ntHeader.delayImportTable.virtualAddress);
      writer.Write(ntHeader.delayImportTable.size);
      writer.Write(ntHeader.cliHeaderTable.virtualAddress);
      writer.Write(ntHeader.cliHeaderTable.size);
      writer.Write((long)0);
    }
    private void WriteSectionHeaders(BinaryWriter/*!*/ writer) 
      //^ requires this.sectionHeaders != null;
    {
      SectionHeader[] sectionHeaders = this.sectionHeaders;
      for (int i = 0, n = this.sectionHeaders.Length; i < n; i++){
        SectionHeader hdr = sectionHeaders[i];
        //^ assume hdr.name != null;
        for (int j = 0, m = hdr.name.Length; j < 8; j++)
          if (j < m) writer.Write(hdr.name[j]); else writer.Write((byte)0);
        writer.Write(hdr.virtualSize);
        writer.Write(hdr.virtualAddress);
        writer.Write(hdr.sizeOfRawData);
        writer.Write(hdr.pointerToRawData);
        writer.Write(hdr.pointerToRelocations);
        writer.Write(hdr.pointerToLinenumbers);
        writer.Write(hdr.numberOfRelocations);
        writer.Write(hdr.numberOfLinenumbers);
        writer.Write(hdr.characteristics);
      }
    }
    private void WriteCLIHeader(BinaryWriter/*!*/ writer) {
      CLIHeader hdr = this.cliHeader;
      writer.Write(hdr.cb);
      writer.Write((ushort)2);
      if (this.UseGenerics)
        writer.Write((ushort)5); //Violates the ECMA standard (25.3.3 of Partition II), but apparently necessary
      else
        writer.Write((ushort)0);
      writer.Write(hdr.metaData.virtualAddress);
      writer.Write(hdr.metaData.size);
      if ((this.peKind & PEKindFlags.Requires32bits) != 0) hdr.flags |= 2;
      if ((this.peKind & PEKindFlags.Prefers32bits) != 0) hdr.flags |= 0x00020000;
      if ((this.peKind & PEKindFlags.ILonly) != 0) hdr.flags |= 1;
      if (this.TrackDebugData) hdr.flags |= 0x10000;
      writer.Write(hdr.flags);
      writer.Write(hdr.entryPointToken);
      writer.Write(hdr.resources.virtualAddress);
      writer.Write(hdr.resources.size);
      writer.Write(hdr.strongNameSignature.virtualAddress);
      writer.Write(hdr.strongNameSignature.size);
      writer.Write(hdr.codeManagerTable.virtualAddress);
      writer.Write(hdr.codeManagerTable.size);
      writer.Write(hdr.vtableFixups.virtualAddress);
      writer.Write(hdr.vtableFixups.size);
    }
    private int WriteImportTableAndEntryPointStub(BinaryWriter/*!*/ writer, ref SectionHeader textSection){
      bool use32bitAddresses = (this.peKind & PEKindFlags.Requires64bits) == 0;
      int pos = (int)writer.BaseStream.Position;
      while (pos % 4 != 0) {pos++; writer.Write((byte)0);}
      int ITrva = textSection.virtualAddress+pos-textSection.pointerToRawData;
      int ITLrva = ITrva + 40;
      int rvasize = 12; // size of relocation sections
      int hintRva = ITLrva + (use32bitAddresses ? 8 : 16);  //position of name of entry point in runtime dll
      int nameRva = hintRva + 14; // position of name of runtime dll
      int ITArva = nameRva + 14 +  // size of name of runtime dll
                             4 + // size of entry point code 0000ff25 
                             rvasize; // size of relocation fixup

      this.ntHeader.addressOfEntryPoint = ITArva - rvasize - 2;
      this.ntHeader.importTable.virtualAddress = ITrva;
      this.ntHeader.importTable.size = this.ntHeader.addressOfEntryPoint-ITrva-2;
      this.ntHeader.importAddressTable.virtualAddress = ITArva;
      this.ntHeader.importAddressTable.size = 8;
      //Import table
      writer.Write((int)ITLrva);
      writer.Write((int)0);
      writer.Write((int)0);
      writer.Write((int)nameRva);
      writer.Write((int)ITArva);
      writer.BaseStream.Position += 20;
      //Import Lookup table
      if (use32bitAddresses) {
        writer.Write((int)hintRva);
        writer.Write((int)0);
      } else {
        writer.Write((long)hintRva);
        writer.Write((long)0);
      }
      //Hint table
      writer.Write((short)0); //Hint
      string entryPointName = this.moduleKind == ModuleKindFlags.DynamicallyLinkedLibrary  ? "_CorDllMain" : "_CorExeMain";
      foreach (char ch in entryPointName.ToCharArray()) writer.Write((byte)ch);
      writer.Write((byte)0);
      //name of CLR runtime dll
      foreach (char ch in "mscoree.dll".ToCharArray()) writer.Write((byte)ch);
      writer.Write((byte)0);
      writer.Write((short)0);
      //entry point code, consisting of a jump indirect to _CorXXXMain
      writer.Write((short)0); //padding so that address to replace is on a word boundary
      writer.Write((byte)0xff);
      writer.Write((byte)0x25);
      writer.Write((int)ITArva + (int)this.ntHeader.imageBase); //REVIEW: is this OK for 64 bit?
      writer.Write((int)0); // relocation fixup must be 12 bytes.
      writer.Write((int)0);
      //Import Address Table
      if (use32bitAddresses) {
        writer.Write((int)hintRva);
        writer.Write((int)0);
      } else {
        writer.Write((long)hintRva);
        writer.Write((long)0);
      }
      //Return RVA of the target address of the indirect jump at the entry point
      return ITArva - rvasize;
    }
    private void WriteReference(BinaryWriter/*!*/ writer, int index, int refSize) {
      if (refSize == 2) writer.Write((short)index); else writer.Write(index);
    }
    private int ComputeStrongNameSignatureSize() {
      int keySize = this.SignatureKeyLength;
      if (keySize == 0)
        keySize = this.PublicKey.Length;
      if (keySize == 0)
        return 0;
      return keySize < 128 + 32 ? 128 : keySize - 32;
    }
  }
#endif
}
